上面的例子来自《Linux环境高级程序设计》- 黄茹,会出现死锁等待的情况,如下两个例子中,一个是对上面的问题的优化,另一个用于熟悉条件变量的使用。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
pthread_mutex_t mutex;
pthread_cond_t empty;
pthread_cond_t notempty;
char buf[32] = {0};
void *producer(void *arg)
{
while (1) {
pthread_mutex_lock(&mutex);
if (strlen(buf)) {
printf("producer waits lock!\n");
pthread_cond_wait(&empty, &mutex);
}
char tmp[] = "Hello";
printf("set data: %s\n", tmp);
strncpy(buf, tmp, sizeof(buf));
pthread_cond_signal(¬empty);
pthread_mutex_unlock(&mutex);
}
return 0;
}
void *consume(void *arg)
{
while (1) {
pthread_mutex_lock(&mutex);
if (0 == strlen(buf)) {
printf("consume waits lock!\n");
pthread_cond_wait(¬empty, &mutex);
}
printf("recv data: %s\n", buf);
memset(buf, 0, sizeof(buf));
sleep(1);
pthread_cond_signal(&empty);
pthread_mutex_unlock(&mutex);
}
return 0;
}
int main(int argc, char *const argv[])
{
pthread_t id1, id2;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&empty, NULL);
pthread_cond_init(¬empty, NULL);
pthread_create(&id1, NULL, producer, NULL);
pthread_create(&id2, NULL, consume, NULL);
sleep(1);
pthread_cond_signal(&empty);
int *ret1;
int *ret2;
pthread_join(id1, (void **)&ret1);
pthread_join(id2, (void **)&ret2);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&empty);
pthread_cond_destroy(¬empty);
return 0;
}
编译:gcc test1.c -lpthread
结果:
$ ./a.out
set data: Hello
producer waits lock!
recv data: Hello
consume waits lock!
set data: Hello
producer waits lock!
recv data: Hello
consume waits lock!
set data: Hello
producer waits lock!
recv data: Hello
consume waits lock!
set data: Hello
producer waits lock!
recv data: Hello
consume waits lock!
set data: Hello
producer waits lock!
recv data: Hello
consume waits lock!
set data: Hello
producer waits lock!
recv data: Hello
...
来自:https://www.cnblogs.com/cyyljw/p/7015774.html
#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE (16)// 缓冲区数量
#define OVER (-1)
struct prodcons
{
// 缓冲区相关数据结构
int buffer[BUFFER_SIZE]; /* 实际数据存放的数组*/
pthread_mutex_t lock; /* 互斥体lock 用于对缓冲区的互斥操作 */
int readpos, writepos; /* 读写指针*/
pthread_cond_t notempty; /* 缓冲区非空的条件变量 */
pthread_cond_t notfull; /* 缓冲区未满的条件变量 */
};
struct prodcons buffer;
/* 初始化缓冲区结构 */
void init(struct prodcons *b)
{
pthread_mutex_init(&b->lock, NULL);
pthread_cond_init(&b->notempty, NULL);
pthread_cond_init(&b->notfull, NULL);
b->readpos = 0;
b->writepos = 0;
}
/* 将产品放入缓冲区,这里是存入一个整数*/
void put(struct prodcons *b, int data)
{
pthread_mutex_lock(&b->lock);
/* 等待缓冲区未满*/
if ((b->writepos + 1) % BUFFER_SIZE == b->readpos) {
printf("put wait lock\n");
pthread_cond_wait(&b->notfull, &b->lock);
}
/* 写数据,并移动指针 */
b->buffer[b->writepos] = data;
b->writepos++;
if (b->writepos >= BUFFER_SIZE) {
b->writepos = 0;
}
/* 设置缓冲区非空的条件变量*/
pthread_cond_signal(&b->notempty);
pthread_mutex_unlock(&b->lock);
}
/* 从缓冲区中取出整数*/
int get(struct prodcons *b)
{
int data = 0;
pthread_mutex_lock(&b->lock);
/* 等待缓冲区非空*/
if (b->writepos == b->readpos) {
printf("get wait lock\n");
pthread_cond_wait(&b->notempty, &b->lock);
}
/* 读数据,移动读指针*/
data = b->buffer[b->readpos];
b->readpos++;
if (b->readpos >= BUFFER_SIZE) {
b->readpos = 0;
}
/* 设置缓冲区未满的条件变量*/
pthread_cond_signal(&b->notfull);
pthread_mutex_unlock(&b->lock);
return data;
}
/* 测试:生产者线程将1 到10000 的整数送入缓冲区,消费者线
程从缓冲区中获取整数,两者都打印信息*/
void *producer(void *data)
{
int n = 0;
for (n = 0; n < 10000; n++) {
printf("%d --->\n", n);
put(&buffer, n);
sleep(1);
}
put(&buffer, OVER);
return NULL;
}
void *consumer(void *data)
{
int d = 0;
while (1) {
d = get(&buffer);
if (d == OVER) {
break;
}
printf("--->%d \n", d);
sleep(1);
}
return NULL;
}
int main(void)
{
pthread_t th_a, th_b;
void *retval;
init(&buffer);
/* 创建生产者和消费者线程*/
pthread_create(&th_a, NULL, producer, 0);
pthread_create(&th_b, NULL, consumer, 0);
/* 等待两个线程结束*/
pthread_join(th_a, &retval);
pthread_join(th_b, &retval);
return 0;
}
编译:gcc test2.c -lpthread
结果:
$ ./a.out
0 --->
get wait lock
--->0
1 --->
--->1
2 --->
--->2
3 --->
--->3
4 --->
--->4
5 --->
--->5
6 --->
--->6
7 --->
--->7
...