一、pthread_cond_wait函数的原理
-
pthread_cond_wait()
用于阻塞当前线程,等待别的线程使用pthread_cond_signal()
或pthread_cond_broadcast
来唤醒它 pthread_cond_wait()
必须与pthread_mutex
配套使用。pthread_cond_wait()
函数一进入wait
状态就会自动release mutex
。当其他线程通过pthread_cond_signal()
或pthread_cond_broadcast
,把该线程唤醒,使pthread_cond_wait()
通过(返回)时,该线程又自动获得该mutex
。
-
pthread_cond_signal
函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal
也会成功返回。
使用pthread_cond_signal
一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal
调用最多发信一次。
- 但是
pthread_cond_signal
在多处理器上可能同时唤醒多个线程,当你只能让一个线程处理某个任务时,其它被唤醒的线程就需要继续
wait
,而且规范要求pthread_cond_signal
至少唤醒一个pthread_cond_wait
上的线程,其实有些实现为了简单在单处理器上也会唤醒多个线程. 另外,某些应用,如线程池,pthread_cond_broadcast
唤醒全部线程,但我们通常只需要一部分线程去做执行任务,所以其它的线程需要继续wait.所以强烈推荐对pthread_cond_wait()
使用while
循环来做条件判断.
#include <>
#include <>
#include <>
#include <>
//链表的结点
struct msg
{
int num;
struct msg *next;
};
struct msg *head = NULL; //头指针
struct msg *temp = NULL; //节点指针
//静态方式初始化互斥锁和条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t has_producer = PTHREAD_COND_INITIALIZER;
void *producer(void *arg)
{
while (1) //线程正常不会解锁,除非收到终止信号
{
pthread_mutex_lock(&mutex); //加锁
temp = malloc(sizeof(struct msg));
temp->num = rand() % 100 + 1;
temp->next = head;
head = temp; //头插法
printf("---producered---%d\n", temp->num);
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_signal(&has_producer); //唤醒消费者线程
usleep(rand() % 3000); //为了使该线程放弃cpu,让结果看起来更加明显。
}
return NULL;
}
void *consumer(void *arg)
{
while (1) //线程正常不会解锁,除非收到终止信号
{
pthread_mutex_lock(&mutex); //加锁
while (head == NULL) //如果共享区域没有数据,则解锁并等待条件变量
{
pthread_cond_wait(&has_producer, &mutex); //我们通常在一个循环内使用该函数
}
temp = head;
head = temp->next;
printf("------------------consumer--%d\n", temp->num);
free(temp); //删除节点,头删法
temp = NULL; //防止野指针
pthread_mutex_unlock(&mutex); //解锁
usleep(rand() % 3000); //为了使该线程放弃cpu,让结果看起来更加明显。
}
return NULL;
}
int main(void)
{
pthread_t ptid, ctid;
srand(time(NULL)); //根据时间摇一个随机数种子
//创建生产者和消费者线程
pthread_create(&ptid, NULL, producer, NULL);
pthread_create(&ctid, NULL, consumer, NULL);
//主线程回收两个子线程
pthread_join(ptid, NULL);
pthread_join(ctid, NULL);
return 0;
}