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 线程条件
- 先解锁mutex,如果mutex没有上锁。系统会报错,退出程序。unlock(data_mutex);
- 等待cond信号
wait(data_cond); - 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线程示列代码