返回信息流开发多线程的系统,难免会遇到同步问题。正确处理线程同步问题是程序运行的关键。而仅仅的通过加锁,还是过于简单,甚至低效。锁一般都配合条件变量来使用。这里面就需要深刻理解系统提供的那几个api函数了。(POSIX)
下面看个例子咯。自己顺便写的,顺便验证一下。
#include <stdio.h>
#include <pthread.h>
#include <time.h>
static int flag = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
void* sub(void* arg)
{
int i = *((int*)arg);
printf("this is thread %d\n", i);
while(1)
{
pthread_mutex_lock(&mutex);
printf("i am thread %d, i get the lock!\n", i);
while(flag == 0)
{
pthread_cond_wait(&cond1, &mutex);
}
printf("i am thread %d, i set flag to 0\n", i);
flag = 0;
pthread_mutex_unlock(&mutex);
printf("i am thread %d, i unlock!\n", i);
pthread_cond_signal(&cond2);
sleep(1);
}
return NULL;
}
void* add(void* arg)
{ int i = *((int*)arg);
printf("this is thread %d\n", i);
while(1)
{
pthread_mutex_lock(&mutex);
printf("i am thread %d, i get the lock!\n", i);
while(flag == 1)
{
pthread_cond_wait(&cond2, &mutex);
}
printf("i am thread %d, i set flag to 1\n", i);
flag = 1;
pthread_mutex_unlock(&mutex);
printf("i am thread %d, i unlock!\n", i);
pthread_cond_broadcast(&cond1);
//pthread_cond_signal(&cond);
sleep(1);
}
return NULL;
}
int main()
{
pthread_t t1, t2, t3;
int n1 = 1;
int n2 = 2;
int n3 = 3;
pthread_create(&t1, NULL, sub, (void*)&n1);
pthread_create(&t2, NULL, sub, (void*)&n2);
sleep(4);
pthread_create(&t3, NULL, add, (void*)&n3);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}
这个程序实现一个简单的功能。一个线程将flag设置成1,而另外两个线程将flag设置成0。
这里面就涉及的同步的问题。
对flag的操作需要加锁是毋庸置疑的。但是绝对不是简单加锁,然后操作那么容易。
首先看线程1,2。
如果执行程序,你会发现,屏幕上会打印出,线程1,2都获得锁的提示。这里面难道出错了么?锁不是只能由一个线程获得么?
其实问题的关键就在,pthread_cond_wait.
这个函数过程比较复杂。首先他会释放锁,等待cond信号发生,进入sleep状态。这就是为什么线程2可以得到锁。2得到锁之后,同样也进入sleep状态。其中
while(flag == 0)
{
pthread_cond_wait(&cond1, &mutex);
}
是必须的。当线程被唤醒的时候他必须要检查条件。这样做的目的有2。
1,因为线程可能错误的被唤醒。
2,考虑如果1线程首先被唤醒,且将flag设置为0,那么,等到2线程执行的时候,它就不能再进行设置。这有点类似生产者消费者的意思。一个生产者,每次生产一个对象,而又两个消费者。每次消费一个对象。所以当2醒来后,因该判断是否有对象消费,如果没有则继续等待唤醒。
所有问题的关键就在于pthread_cond_wait的行为。首先是解锁,然后等待被唤醒,之后在加锁。也就是说,pthread_cond_wait调用之前,线程拥有锁,返回之后线程也拥有锁。
如果仅仅是简单的这样操作,会造成混乱的:
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond1, &mutex);
同时要注意,一个信号量只能拥有一个锁,而一个锁可以给多个信号量。
还有,pthread_cond_signal只能唤醒一个线程,到底是哪一个,又内核调度决定。
pthread_cond_broadcast唤醒所有线程。有可能会把不想唤醒的线程唤醒。此时的同步问题需要程序员解决。好比那个while判断。
就看了这些了。hoho
这是一条镜像帖。来源:北邮人论坛 / soft-design / #27148同步于 2008/6/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
SoftDesign机器人发帖
线程同步心得
redfox
2008/6/19镜像同步9 回复
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
POSIX Threads 不是M$的
【 在 kowizards 的大作中提到: 】
: 顶你的分享行为!
: 顺便问一下,pthread是微软的线程库吗?
: 另外你知道ZThread库怎么装吗?
很好 应该更深入一下
【 在 redfox (redfox) 的大作中提到: 】
: 开发多线程的系统,难免会遇到同步问题。正确处理线程同步问题是程序运行的关键。而仅仅的通过加锁,还是过于简单,甚至低效。锁一般都配合条件变量来使用。这里面就需要深刻理解系统提供的那几个api函数了。(POSIX)
: 下面看个例子咯。自己顺便写的,顺便验证一下。
: #include <stdio.h>
: ...................
【 在 ericyosho 的大作中提到: 】
: 这么说,是不是有这样一个原则,只要是会从wait中醒过来的,必须要加while和条件的判断?
一般是都要这样写的,就是上面提到的两个原因。
1.唤醒的线程不可确定
2.pthread_conf_broadcast