全部博文(333)
分类: LINUX
2016-07-04 17:55:33
//pthread_cond_signal 只发信号,内部不会解锁,在Linux 线程中,有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。(pthread_cond_signal unlock后pthread_cond_wait才能上锁)
//pthread_cond_wait 先解锁,等待,有信号来,上锁,执行while检查防止另外的线程更改条件
//循环判断的原因如下:假设2个线程在getq阻塞,然后两者都被激活,而其中一个线程运行比较块,快速消耗了2个数据,另一个线程醒来的时候已经没有新 数据可以消耗了。另一点,man pthread_cond_wait可以看到,该函数可以被信号中断返回,此时返回EINTR。为避免以上任何一点,都必须醒来后再次判断睡眠条件。更 正:pthread_cond_wait是信号安全的系统调用,不会被信号中断, (不是说wai来到后再走一次while)
条件锁(条件Mutex)pthread_cond_wait、pthread_cond_signal、pthread_cond_broadcast的使用收藏
pthread_cond_wait()的工作流程如下(以MAN中的EXAMPLE为例):
Consider two shared variables x and y, protected by the mutex mut, and a condition vari-
able cond that is to be signaled whenever x becomes greater than y.
int x,y;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Waiting until x is greater than y is performed as follows:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
Modifications on x and y that may cause x to become greater than y should signal the con-
dition if needed:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_singal(&cond);
pthread_mutex_unlock(&mut);
这个例子的意思是,两个线程要修改X和
Y的值,第一个线程当X<=Y时就挂起,直到X>Y时才继续执行(由第二个线程可能会修改X,Y的值,当X>Y时唤醒第一个线程),即
首先初始化一个普通互斥量mut和一个条件变量cond。之后分别在两个线程中分别执行如下函数体:
pthread_mutex_lock(&mut);
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
/* operate on x and y */
pthread_mutex_unlock(&mut);
和: pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mut);
其实函数的执行过程非常简单,在第一个线程执行到pthread_cond_wait(&cond,&mut)时,此时如果
X<=Y,则此函数就将mut互斥量解锁,再将cond条件变量加锁 ,此时第一个线程挂起 (不占用任何CPU周期)。
而在第二个线程中,本来因为mut被第一个线程锁住而阻塞,此时因为mut已经释放,所以可以获得锁mut,并且进行修改X和Y的值,在修改之后,一个
IF语句判定是不是X>Y,如果是,则此时pthread_cond_signal()函数会唤醒第一个线程,并在下一句中释放互斥量mut。然后
第一个线程开始从pthread_cond_wait()执行,首先要再次锁mut , 如果锁成功,再进行条件的判断
(至于为什么用WHILE,即在被唤醒之后还要再判断,后面有原因分析),如果满足条件,则被唤醒进行处理,最后释放互斥量mut 。
至于为什么在被唤醒之后还要再次进行条件判断(即为什么要使用while循环来判断条件),是因为可能有“惊群效应”。有人觉得此处既然是被唤醒的,肯定
是满足条件了,其实不然。如果是多个线程都在等待这个条件,而同时只能有一个线程进行处理,此时就必须要再次条件判断,以使只有一个线程进入临界区处理。
对此,转来一段:
引用下POSIX的RATIONALE:
Condition Wait Semantics
It
is important to note that when pthread_cond_wait() and
pthread_cond_timedwait() return without error, the associated predicate
may still be false. Similarly, when pthread_cond_timedwait() returns
with the timeout error, the associated predicate may be true due to an
unavoidable race between the expiration of the timeout and the predicate
state change.
The
application needs to recheck the predicate on any return because it
cannot be sure there is another thread waiting on the thread to handle
the signal, and if there is not then the signal is lost. The burden is
on the application to check the predicate.
Some
implementations, particularly on a multi-processor, may sometimes cause
multiple threads to wake up when the condition variable is signaled
simultaneously on different processors.
In
general, whenever a condition wait returns, the thread has to
re-evaluate the predicate associated with the condition wait to
determine whether it can safely proceed, should wait again, or should
declare a timeout. A return from the wait does not imply that the
associated predicate is either true or false.
It is thus recommended that a condition wait be enclosed in the equivalent of a "while loop" that checks the predicate.
从上文可以看出:
1,pthread_cond_signal
在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续
wait,while循环的意义就体现在这里了,而且规范要求pthread_cond_signal至少唤醒一个pthread_cond_wait上
的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程.
2,某些应用,如线程池,pthread_cond_broadcast唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐此处使用while循环.
其实说白了很简单,就是pthread_cond_signal()也可能唤醒多个线程,而如果你同时只允许一个线程访问的话,就必须要使用while来进行条件判断,以保证临界区内只有一个线程在处理。
#include
#include
#include
#include
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /*初始化互斥锁*/
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; /*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //初始化条件变量
void *thread1(void *);
void *thread2(void *);
int i=1;
int main(void)
{
pthread_t t_a;
pthread_t t_b;
pthread_create(&t_a,NULL,thread1,(void *)NULL);/*创建进程t_a*/
pthread_create(&t_b,NULL,thread2,(void *)NULL); /*创建进程t_b*/
pthread_join(t_b, NULL);/*等待进程t_b结束*/
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex1);
pthread_cond_destroy(&cond);
exit(0);
}
void *thread1(void *junk)
{
for(i=1;i<=9;i++)
{
printf("IN one\n");
pthread_mutex_lock(&mutex);//
if(i%3==0)
pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/
else
printf("thead1:%d\n",i);
pthread_mutex_unlock(&mutex);//*解锁互斥量*/
printf("Up Mutex\n");
sleep(10);
}
}
void *thread2(void *junk)
{
while(i<9)
{
printf("IN two \n");
pthread_mutex_lock(&mutex);
if(i%3!=0)
// pthread_cond_wait(&cond,&mutex1);/*等待*/
pthread_cond_wait(&cond,&mutex);/*等待*/
printf("thread2:%d\n",i);
pthread_mutex_unlock(&mutex);
printf("Down Mutex\n");
sleep(10);
}
}