pthread_cond_wait的等待和激发
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pthread_cond_wait的等待和激发相关的知识,希望对你有一定的参考价值。
参考技术Aint pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
等待条件有两种方式:条件等待pthread_cond_wait()和计时等待pthread_cond_timedwait(),其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEOUT,结束等待,其中abstime以与time()系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的竞争条件(Race Condition)。mutex互斥锁必须是普通锁(PTHREAD_MUTEX_TIMED_NP)或者适应锁(PTHREAD_MUTEX_ADAPTIVE_NP),且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。
现在来看一段典型的应用:看注释即可。 #include<pthread.h>#include<unistd.h>#include<stdio.h>#include<string.h>#include<stdlib.h>static pthread_mutex_t mtx=PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t cond=PTHREAD_COND_INITIALIZER;struct node int n_number; struct node *n_next; *head=NULL; /*[thread_func]*//*释放节点内存*/static void cleanup_handler(void*arg) printf(Clean up handler of second thread.\\n); free(arg); (void)pthread_mutex_unlock(&mtx);static void *thread_func(void *arg) struct node*p=NULL; pthread_cleanup_push(cleanup_handler,p); pthread_mutex_lock(&mtx); //这个mutex_lock主要是用来保护wait等待临界时期的情况, //当在wait为放入队列时,这时,已经存在Head条件等待激活 //的条件,此时可能会漏掉这种处理 //这个while要特别说明一下,单个pthread_cond_wait功能很完善, //为何这里要有一个while(head==NULL)呢?因为pthread_cond_wait //里的线程可能会被意外唤醒,如果这个时候head==NULL, //则不是我们想要的情况。这个时候, //应该让线程继续进入pthread_cond_wait while(1) while(head==NULL) pthread_cond_wait(&cond,&mtx); //pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx, //然后阻塞在等待队列里休眠,直到再次被唤醒 //(大多数情况下是等待的条件成立而被唤醒,唤醒后, //该进程会先锁定先pthread_mutex_lock(&mtx);, //再读取资源用这个流程是比较清楚的 /*block-->unlock-->wait()return-->lock*/ p=head; head=head->n_next; printf(Got%dfromfrontofqueue\\n,p->n_number); free(p); pthread_mutex_unlock(&mtx);//临界区数据操作完毕,释放互斥锁 pthread_cleanup_pop(0); return 0;int main(void) pthread_t tid; int i; struct node *p; pthread_create(&tid,NULL,thread_func,NULL); //子线程会一直等待资源,类似生产者和消费者, //但是这里的消费者可以是多个消费者, //而不仅仅支持普通的单个消费者,这个模型虽然简单, //但是很强大 for(i=0;i<10;i++) p=(struct node*)malloc(sizeof(struct node)); p->n_number=i; pthread_mutex_lock(&mtx);//需要操作head这个临界资源,先加锁, p->n_next=head; head=p; pthread_cond_signal(&cond); pthread_mutex_unlock(&mtx);//解锁 sleep(1); printf(thread1wannaendthecancelthread2.\\n); pthread_cancel(tid); //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程, //子线程会在最近的取消点,退出线程,而在我们的代码里,最近的 //取消点肯定就是pthread_cond_wait()了。 pthread_join(tid,NULL); printf(Alldone--exiting\\n); return 0;
waitpid 和 pthread_cond_wait(3)
【中文标题】waitpid 和 pthread_cond_wait(3)【英文标题】:waitpid and pthread_cond_wait(3) 【发布时间】:2012-09-06 12:11:58 【问题描述】:我正在开发一个使用生产者和消费者线程的 linux 应用程序。这是一个相当成熟的应用程序,我不想过多地改变架构。
生产者和消费者线程通过等待队列链接。这是一个通过 std::queue 以及条件变量和互斥锁实现的类。
现在我希望消费者线程能够派生/执行子进程,并等待子进程完成或可等待队列非空,以先发生者为准。如果等待队列不为空,则必须终止子进程。 编辑:子进程是无法更改的第三方应用程序。
一种可能性是当子进程终止时在我的条件变量上调用 pthread_cond_signal(),但如何实现呢?我不能使用 SIGCHLD 的处理程序,至少不能直接使用,因为man page 说 pthread_cond_signal() 不能从信号处理程序中使用。
一种可能的方法是产生子进程,然后启动一个线程到阻塞的 waitpid(),最后是 pthread_cond_signal()。不过,这似乎有点笨拙:我真的需要生成一个线程来监视 pid 吗?
对于混合 waitpid 和 select/poll/epoll,有 Self Pipe Trick。混合等待PID和条件变量是否有任何等价物?
注意 1: 在某些实现中,SIGCHLD 会中断条件变量等待函数。这不是可移植的,如果可能的话,我宁愿不依赖这种行为。
注意 2: 由于条件变量封装在可等待队列类中,我需要扩展该类以允许应用程序向互斥体发出信号。这只是一个微不足道的实现细节,我在我的问题中已经掩饰了。
【问题讨论】:
@user1548637:有趣的想法,但我无法更改子应用程序。他们都是第三者。为了清楚起见,我会将其添加到我的问题中。 @user1548637:您对帮助应用程序的建议会很好,因为那时我只需要一个帮助应用程序来处理所有不同的子应用程序。如果可能的话,我仍然想要一个不涉及额外进程或线程开销的解决方案。 因为你不能让你的子进程做任何类型的工作(这对于让它与你交互是必要的),你可能不会有任何其他的解决方案,而不是执行多个锁定功能(在不同的线程中)。虽然我可以想到其他方式,但我不确定您是否可以从信号处理程序内部发出信号。 或者如果你可以使用信号量锁,它也可以代替发出信号(但我认为这是可能的)。你知道吗? @user1548637:信号量的唯一问题是我需要使用仅适用于 CLOCK_REALTIME 的 sem_timedwait()。条件变量通过 pthread_condattr_setclock() 允许 CLOCK_MONOTONIC 作为选项。这对我来说很重要,因为目标平台可能会不时地重新同步其系统时钟。我将研究将 CLOCK_MONOTONIC 与信号量一起使用的方法...... 【参考方案1】:也许这行得通,但我不确定:
创建一个信号量,该信号量将在您的等待队列中注册,并在等待队列本身要更改其自己的锁以指示状态更改时锁定/更改/解锁。你应该在它持有信号量的同时改变它自己的互斥锁。
为SIGCHLD
实现一个信号处理程序,然后在第 3 方应用程序终止时执行信号量锁定/更改/解锁,如果不是这种情况,则不执行任何操作。
在上述情况下,他们将等待 1 并在您的信号量上递增(作为一个信号量操作),当他们想要获取信号量锁时,然后做他们的工作然后更改信号量到 0(减 2)以便为您的等待线程解锁它。这样,您就不会从任何队列/第 3 方应用程序中连续获得两个成功的锁。
在您的实际线程中,应该等待第 3 方应用程序终止或等待队列,您基本上让它在等待 0 时等待同一信号量上的锁定(并减少它,如果有其他服务员为 0)。如果获得了锁,则检查等待队列上的互斥锁是否已释放。如果没有,您知道您的第 3 方应用程序已终止。您执行您的工作,然后通过递增将信号量更改为 1,从而再次为您的队列和第 3 方应用程序解锁信号量。
由于信号处理程序可以中断semop(2)
-lock 调用,因此您必须检查EINTR
并循环您的任何锁定尝试。
如果保证信号处理程序将完成它的执行(我认为确实如此),这可能会起作用。
【讨论】:
以上是关于pthread_cond_wait的等待和激发的主要内容,如果未能解决你的问题,请参考以下文章
pthread_cond_wait 和 pthread_mutex_lock 优先级?
Linux C语言 pthread_cond_wait()pthread_cond_timedwait()函数(不允许cond被唤醒时产生竞争,所以需要和互斥锁搭配)