六、GLib线程

1线程和进程

1.1 基本概念

  进程是系统进行资源分配和调度的一个独立单位。
  线程运行在进程中,线程是进程的一个实体,是CPU调度和分配的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不用有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器、栈),但是他可与同属一个进程的其他线程共享进程所拥有的全部资源。

1.2 关系

  一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。

1.3 区别

  进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且有要共享某些变量的并发操作,只能用线程,不能用进程。

  • 简而言之,一个程序至少有一个进程,一个进程至少有一个线程。
  • 线程的划分尺度小于进程,使得多线程程序的并发性高。
  • 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大提高了程序运行效率。
  • 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
  • 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看作多个独立的应用,来实现进程的调度和管理以及资源分配。

1.4 总结

  进程是系统分配资源的最小单位,根据不同应用程序(车辆)进行分配资源。多个线程(洗车工、美容工、修理工)运行在线程(一个车辆)中,进行不同任务。一个进程中的多个线程引发了异步同步等问题。
请添加图片描述

2 多线程中并发、并行、同步和异步的区别

3 GLib多线程

3.1 线程初始化

  因为后续版本GLib默认初始化线程,一般不需要去用户初始化,开头最好检查一下是否初始化。

if (!g_thread_supported ()) g_thread_init (NULL);

3.2 创建线程

GThread * g_thread_new     (const gchar    *name,
                            GThreadFunc     func,
                            gpointer        data);
GThread* g_thread_create  (GThreadFunc func,
                           gpointer data,
                           gboolean joinable,
                           GError **error);

  如果joinable是TRUE,就可以使用g_thread_join()等待这个线程结束。

3.3 互斥锁

  如果mutex早已被其他线程上锁,现在的线程就会阻塞在这里,等待mutex被其他线程解锁。GMutex既不能保证是递归的也不能保证是非递归的。因此,在已经被同一个线程锁定的GMutex上调用g_mutex_lock()会导致未定义的行为(包括但不限于死锁)。单线程重复加锁会导致死锁

void  g_mutex_lock  (GMutex *mutex);

  尝试去上锁,如果mutex被其他线程上锁情况下,返回FALSE,反则现在的线程就可以上锁,返回TRUE。

gboolean g_mutex_trylock (GMutex *mutex);

  解锁mutex。

void g_mutex_unlock (GMutex *mutex);

  销毁锁。

void  g_mutex_free (GMutex *mutex);

3.4 线程条件

  1. 先解锁mutex,如果mutex没有上锁。系统会报错,退出程序。unlock(data_mutex);
  2. 等待cond信号
    wait(data_cond);
  3. mutex上锁
    lock(data_mutex);

  等待cond信号。这样才退出阻塞。同时会给mutex上锁。

void  g_cond_wait  (GCond *cond,
                    GMutex *mutex);

3.5 创建锁对象和释放

GCond *         g_cond_new              (void);
GMutex *        g_mutex_new             (void);
void            g_mutex_free            (GMutex *mutex);
void            g_cond_free             (GCond  *cond);

3.6 示列代码

#include <glib.h>

/* g_mutex_lock is a macro that uses the dll global variable
 * g_thread_functions_for_glib_use. To use the global variable
 * we must include glib_global.h.
 */
#include <glib_global.h> // Always include as the last include.

#define NTHREADS 5

int no_threads = 0;
GMutex *mutex;
GCond *cond; 

void* thread_function(void *data)
{
	/*
	.
	local data declaration
	.
	 */
	
	// lock on the mutex before changing the global variable no_threads
	g_mutex_lock(mutex);
	no_threads++;
	
	//do a broadcast on the conditional variable once NTHREDS have been created
	if(no_threads == NTHREADS)
		g_cond_broadcast(cond);
	
	//unlock the mutex
	g_mutex_unlock(mutex);

	/*
	.
	some code
	.
	 */
	
	return NULL;
 	
}

int main ()
{
	int i;
	GThread *thread[NTHREADS];
	/*
	 .
	 other local data declaration
	 .
 	 */ 

	
	if(!g_thread_supported())
		g_thread_init (NULL);
	
	mutex = g_mutex_new ();
	cond = g_cond_new (); 
 	
	for(i=0; i<NTHREADS; i++)
		thread[i] = g_thread_create(thread_function, NULL,TRUE, NULL);
	
	g_mutex_lock (mutex);
	
	if (no_threads < NTHREADS)
g_cond_wait (cond, mutex);
	
	g_mutex_unlock (mutex);
	
	/*
	.
	some code
	.
	 */
	 
	for(i=0; i<NTHREADS; i++)
		g_thread_join(thread[i]);
	 
	g_mutex_free(mutex);
	g_cond_free(cond);
	
	/*
	.
	some code
	.
	 */
	 
	return 0;
}

4 互斥锁代码

#include<glib.h>
#include<glib/gprintf.h>
#include<unistd.h>
#include<sys/syscall.h>

G_LOCK_DEFINE(thread_mutex);
gint count = 0;

gpointer
thread_func1(gpointer data){
  gint tmp;
  while(1){
    G_LOCK(thread_mutex);
    g_print("%s %ld count: %d\n", __func__, syscall(__NR_gettid), count);
    tmp = count;
    count++;
    g_usleep(2000000);
    g_print("%s %ld count++ tmp: %d count: %d\n", __func__, syscall(__NR_gettid), tmp, count);
    G_UNLOCK(thread_mutex);
    g_usleep(20000);
  }
}

gpointer
thread_func2(gpointer data){
  gint tmp;
  while(1){
    G_LOCK(thread_mutex);
    g_print("%s %ld count: %d\n", __func__, syscall(__NR_gettid), count);
    tmp = count;
    count++;
    g_usleep(2000000);
    g_print("%s %ld count++ tmp: %d count: %d\n", __func__, syscall(__NR_gettid), tmp, count);
    G_UNLOCK(thread_mutex);
    g_usleep(20000);
  }
}

int
main(int argc, char *argv[]){
  g_print("main in\n");
  GThread *gthread1 = NULL, *gthread2 = NULL;
  gthread1 = g_thread_new("func1", thread_func1, NULL);
  gthread2 = g_thread_new("func2", thread_func2, NULL);
  g_thread_join(gthread1);
  g_thread_join(gthread2);

  g_print("main out\n");
  return 0;
}

5 条件锁代码

#include<glib.h>
#include<glib/gprintf.h>
#include<unistd.h>
#include<sys/syscall.h>

GMutex *thread_mutex, *broad_mutex;
GCond *cond1, *broad_cond;
gint count = 0, broad_flag = 0;

gpointer
decrement(gpointer data){
  g_mutex_lock(thread_mutex);
  g_print("%s in\n", __func__);

  while(count == 0){
    g_print("***wait***\n");
    g_cond_wait(cond1, thread_mutex);}
  g_print("****What***");
  count--;
  g_print("%s decrement: %d.\n", __func__, count);
  g_print("out decrement.\n");

  g_mutex_unlock(thread_mutex);
  g_print("%s out\n", __func__);
  return NULL;
}

gpointer 
increment(gpointer data){
  g_mutex_lock(thread_mutex);
  g_print("%s in\n", __func__);

  count++;
  g_print("%s increment:%d.\n", __func__, count);
  if(count != 0)
    g_cond_signal(cond1);
  g_mutex_unlock(thread_mutex);
  g_print("%s out\n", __func__);
  return NULL;
}

gpointer 
broadcast(gpointer data){
  g_print("%s in\n", __func__);
  g_usleep(5000000);
  g_mutex_lock(broad_mutex);

  broad_flag = 1;
  g_cond_broadcast(broad_cond);
  g_mutex_unlock(broad_mutex);
  g_print("%s out\n", __func__);
  return NULL;
}

gpointer 
trigger1(gpointer data){
  g_print("%s in\n", __func__);
  g_mutex_lock(broad_mutex);

  while(broad_flag == 0)
    g_cond_wait(broad_cond, broad_mutex);
  g_print("%s recv broad_cond\n", __func__);

  g_mutex_unlock(broad_mutex);
  g_print("%s out\n", __func__);
}

gpointer 
trigger2(gpointer data){
  g_print("%s in\n", __func__);
  g_mutex_lock(broad_mutex);

  while(broad_flag == 0)
    g_cond_wait(broad_cond, broad_mutex);
  g_print("%s recv broad_cond\n", __func__);

  g_mutex_unlock(broad_mutex);
  g_print("%s out\n", __func__);
}

gpointer 
trigger3(gpointer data){
  g_print("%s in\n", __func__);
  g_mutex_lock(broad_mutex);

  while(broad_flag == 0)
    g_cond_wait(broad_cond, broad_mutex);
  g_print("%s recv broad_cond\n", __func__);

  g_mutex_unlock(broad_mutex);
  g_print("%s out\n", __func__);
}

int 
main(int argc, char *argv[]){
  g_print("main in\n");
  GThread *gthread1 = NULL, *gthread2 = NULL;
  cond1 = g_new(GCond, 1);
  g_cond_init(cond1);

  thread_mutex = g_new(GMutex, 1);
  g_mutex_init(thread_mutex);

  gthread1 = g_thread_new("func1", decrement, NULL);
  g_usleep(5000000);
  gthread2 = g_thread_new("func2", increment, NULL);
  g_thread_join(gthread1);
  g_thread_join(gthread2);

  g_mutex_clear(thread_mutex);
  g_cond_clear(cond1);

  g_printf ("----------broadcast cond test-----------\n");
	GThread *gthread3 = NULL, *gthread4 = NULL;
	broad_cond = g_new(GCond, 1);
	g_cond_init (broad_cond);
	broad_mutex = g_new(GMutex, 1);
	g_mutex_init (broad_mutex);
	
	gthread1 = g_thread_new ("broadcast", broadcast, NULL);
	gthread2 = g_thread_new ("trigger1", trigger1, NULL);
	gthread3 = g_thread_new ("trigger2", trigger2, NULL);
	gthread4 = g_thread_new ("trigger3", trigger3, NULL);
	g_thread_join (gthread1);
	g_thread_join (gthread2);
	g_thread_join (gthread3);
	g_thread_join (gthread4);
	
	g_mutex_clear (broad_mutex);
	g_cond_clear(broad_cond);
	
	g_printf ("main out\n");
   g_thread_foreach  
  return 0;
}

6 总结

/* @brief:  这是一个阻塞函数、一直等待thread线程结束
 * @return: 线程函数的返回值。
 */
gpointer g_thread_join (GThread *thread);
/* @brief: 放在Glib创建的线程函数中,使用该函数可以直接退出线程。
 * @retval: 线程需要返回的指针
 */
void g_thread_exit (gpointer retval);

参考1:进程和线程关系及区别
参考2:并发 并行 同步 异步 多线程的区别
参考3:进程和线程、并发和并行、同步和异步
参考4:Glib多线程编程
参考5:浅析GLib, Glib多线程编程
参考6:本文例程代码参考博客
参考7:GLib Reference Manual
参考8:一些GLib函数中文翻译
参考9:GLib线程示列代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值