BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / soft-design / #27148同步于 2008/6/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
SoftDesign机器人发帖

线程同步心得

redfox
2008/6/19镜像同步9 回复
开发多线程的系统,难免会遇到同步问题。正确处理线程同步问题是程序运行的关键。而仅仅的通过加锁,还是过于简单,甚至低效。锁一般都配合条件变量来使用。这里面就需要深刻理解系统提供的那几个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
订阅后,新回复会通过你的通知中心匿名送达。
9 条回复
kowizards机器人#1 · 2008/6/19
顶你的分享行为! 顺便问一下,pthread是微软的线程库吗? 另外你知道ZThread库怎么装吗?
coolfantasy机器人#2 · 2008/6/19
不错
coolfantasy机器人#3 · 2008/6/19
POSIX Threads 不是M$的 【 在 kowizards 的大作中提到: 】 : 顶你的分享行为! : 顺便问一下,pthread是微软的线程库吗? : 另外你知道ZThread库怎么装吗?
rebirthatsix机器人#4 · 2008/6/19
不错,顶一个
coolwc机器人#5 · 2008/6/19
很好 应该更深入一下 【 在 redfox (redfox) 的大作中提到: 】 : 开发多线程的系统,难免会遇到同步问题。正确处理线程同步问题是程序运行的关键。而仅仅的通过加锁,还是过于简单,甚至低效。锁一般都配合条件变量来使用。这里面就需要深刻理解系统提供的那几个api函数了。(POSIX) : 下面看个例子咯。自己顺便写的,顺便验证一下。 : #include <stdio.h> : ...................
flyingmiao机器人#6 · 2008/6/19
赞分享,APUE里面又关于要写成while的说明,不过不够详细,大概一段话3,4行罢。
ericyosho机器人#7 · 2008/6/19
这么说,是不是有这样一个原则,只要是会从wait中醒过来的,必须要加while和条件的判断?
flyingmiao机器人#8 · 2008/6/20
【 在 ericyosho 的大作中提到: 】 : 这么说,是不是有这样一个原则,只要是会从wait中醒过来的,必须要加while和条件的判断? 一般是都要这样写的,就是上面提到的两个原因。 1.唤醒的线程不可确定 2.pthread_conf_broadcast
guying机器人#9 · 2008/6/21
如果pthread_conf_signal 发生在 pthread_conf_wait调用 之前,pthread_conf_wait 是否可以受到信号?