Linux系统编程——多线程之条件变量pthread_cond_t、pthread_cond_wait使用

多线程之条件变量pthread_cond_t、pthread_cond_wait使用

以下代码看起来没有什么问题,但是编译运行多次后,就有可能出现问题。

//使用条件变量实现生产者和消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
typedef struct node
{
	int data;
	struct node *next;
}NODE;

NODE *head = NULL;

//定义一把锁
pthread_mutex_t mutex;

//定义条件变量
pthread_cond_t cond;

//生产者线程
void *producer(void *arg)
{
	NODE *pNode = NULL;
	int n = *(int *)arg;
	while(1)
	{
		//生产一个节点
		pNode = (NODE *)malloc(sizeof(NODE));
		if(pNode==NULL)
		{
			perror("malloc error");
			exit(-1);
		}
		pNode->data = rand()%1000;
		printf("P[%d]:[%d]\n", n, pNode->data);

		//加锁
		pthread_mutex_lock(&mutex);

		pNode->next = head;
		head = pNode;

		//解锁
		pthread_mutex_unlock(&mutex);

		//通知消费者线程解除阻塞
		pthread_cond_signal(&cond);

		sleep(rand()%3);
	}
}


//消费者线程
void *consumer(void *arg)
{
	NODE *pNode = NULL;
	int n = *(int *)arg;
	while(1)
	{
		//加锁
		pthread_mutex_lock(&mutex);

		if(head==NULL)
		{
			//若条件不满足,需要阻塞等待
			//若条件不满足,则阻塞等待并解锁;
			//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁 
			pthread_cond_wait(&cond, &mutex);
		}
		
		//007
		
		printf("C[%d]:[%d]\n", n, head->data);	
		pNode = head;
		head = head->next;

		//解锁
		pthread_mutex_unlock(&mutex);

		free(pNode);
		pNode = NULL;

		sleep(rand()%3);
	}
}

int main()
{
	int ret;
	int i = 0;
	pthread_t thread1[5];
	pthread_t thread2[5];

	//初始化互斥锁
	pthread_mutex_init(&mutex, NULL);

	//条件变量初始化
	pthread_cond_init(&cond, NULL);

	int arr[5];
	for(i=0; i<5; i++)
	{
		arr[i]= i;
		//创建生产者线程
		ret = pthread_create(&thread1[i], NULL, producer, &arr[i]);
		if(ret!=0)
		{
			printf("pthread_create error, [%s]\n", strerror(ret));
			return -1;
		}

		//创建消费者线程
		ret = pthread_create(&thread2[i], NULL, consumer, &arr[i]);
		if(ret!=0)
		{
			printf("pthread_create error, [%s]\n", strerror(ret));
			return -1;
		}
	}

	//等待线程结束
	for(i=0; i<5; i++)
	{
		pthread_join(thread1[i], NULL);
		pthread_join(thread2[i], NULL);
	}

	//释放互斥锁
	pthread_mutex_destroy(&mutex);

	//释放条件变量
	pthread_cond_destroy(&cond);

	return 0;
}

编译代码gcc -o a.out 03-pthread_cond_mul.c -lpthread

$ ./a.out 
P[1]:[886]
P[3]:[915]
C[0]:[915]
C[1]:[886]
P[4]:[649]
P[2]:[777]
C[2]:[777]
C[1]:[649]
P[0]:[383]
C[3]:[383]
P[4]:[926]
P[4]:[426]
P[3]:[736]
C[4]:[426]
C[0]:[736]
C[0]:[926]
P[0]:[782]
C[2]:[782]
Segmentation fault (core dumped)
$ 

分析代码,不难发现,问题有很大概率出现在消费者代码段。

		printf("C[%d]:[%d]\n", n, head->data);	
		pNode = head;
		head = head->next;

pthread_cond_wait唤醒多个线程,先消费的处导致head->data访问出错。代码修改如下

		if(head==NULL)
		{
			//若条件不满足,需要阻塞等待
			//若条件不满足,则阻塞等待并解锁;
			//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁 
			pthread_cond_wait(&cond, &mutex);
		}
		
		if(head==NULL)
		{
			//解锁
			pthread_mutex_unlock(&mutex);	
			continue;
		}

总结

多个生成者和多个消费者程序在执行的时候core掉的原因分析:
假若只有一个生产者生产了一个节点, 此时会调用pthread_cond_signal通知
消费者线程, 此时若有多个消费者被唤醒了, 则最终只有消费者获得锁, 然后进行
消费, 此时会将head置为NULL, 然后其余的几个消费者线程只会有一个线程获得锁,
然后读取head的内容就会core掉.

在使用条件变量的线程中, 能够引起线程的阻塞的地方有两个:
1 在条件变量处引起阻塞---->这个阻塞会被pthread_cond_signal解除阻塞
2 互斥锁也会使线程引起阻塞----->其他线程解锁会使该线程解除阻塞.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值