前言
线程同步属于操作系统方面的知识,它不属于某个具体的语言,也不属于某个具体的库
所有支持线程的语言,都有类似的API,所以我把这篇博客既归到Java专栏,又归到C++专栏里
要研究的问题
原因分析
其实,这个问题并不难
之所以很多人觉得难,是因为没有真正搞清楚自己想要干什么,看到别人这么用,就想盲目拿来用
首先,互斥体mutex大家应该都很容易理解,就是给资源上锁,防止并发操作,导致程序异常
条件变量condition的作用,则是等待资源的某个具体状态发生时,再执行代码
那么,答案就很清楚了,因为状态是属于某个具体资源的,如果没有mutex的保证,状态判断可能也是错误的
举个栗子
比如说,mutex控制的资源是一个数组
A线程,要在数组为空时,去做一些事情,就会等待condition-a
B线程,要在数组数量大于100时,去做一些事情,就会等待condition-b
C线程,在对数组进行一波操作之后
判断a条件符合,则发出一个condition-a成立的信号,如果b条件符合,则发出一个condition-b成立的信号
这样,问题一就可以很好地解释了
至于问题二,如果等待condition时不释放mutex的话,那么其它线程永远无法改变资源的状态,条件永远也不可能成立
优点分析
使用condition的好处是,我们对资源的访问控制更加精细
我们只等待某个具体的状态,而不是资源一发生变化,就唤醒所有线程
这样不但会造成资源浪费,并且代码可读性也不强,线程被唤醒后,如果不符合条件还要重新退回等待状态
代码示例
简单以C语言SDL库为例,说明mutex和cond的使用格式,其它语言或框架大致类似
#include <SDL.h>
#include <stdio.h>
SDL_mutex *mutex = NULL;
SDL_cond *cond = NULL;
int thread_work(void *arg) {
printf("Thread-2 Lock Mutex Start\n");
SDL_LockMutex(mutex);
printf("Thread-2 Lock Mutex Success\n");
printf("Thread-2 Working with Mutex\n");
sleep(4);
printf("Thread-2 Wait Condition Start\n");
SDL_CondWait(cond, mutex);
printf("Thread-2 Wait Condition Success\n");
printf("Thread-2 Unlock Mutex\n");
SDL_UnlockMutex(mutex);
printf("Thread-2 Finish\n");
return 0;
}
#undef main
int main() {
mutex = SDL_CreateMutex();
cond = SDL_CreateCond();
SDL_Thread *t = SDL_CreateThread(thread_work, "Thread-2", NULL);
printf("Thread-1 Working\n");
sleep(2);
printf("Thread-1 Lock Mutex Start\n");
SDL_LockMutex(mutex);
printf("Thread-1 Lock Mutex Success\n");
printf("Thread-1 Working with Mutex\n");
sleep(2);
printf("Thread-1 Send Condition Signal\n");
SDL_CondSignal(cond);
printf("Thread-1 Working with Mutex\n");
sleep(2);
printf("Thread-1 Unlock Mutex\n");
SDL_UnlockMutex(mutex);
printf("Thread-1 Wait Thread-2 Finish Start\n");
SDL_WaitThread(t, NULL);
printf("Thread-1 Wait Thread-2 Finish Success\n");
printf("Thread-1 Destroy Mutex Start\n");
printf("Thread-1 Destroy Condition Start\n");
SDL_DestroyMutex(mutex);
SDL_DestroyCond(cond);
printf("Thread-1 Destroy Mutex Success\n");
printf("Thread-1 Destroy Condition Success\n");
return 0;
}