问题描述及思路见:使用互斥锁和条件变量实现生产者消费者模型
本文源代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
sem_t semp; //生产者信号量
sem_t semc; //消费者信号量
pthread_mutex_t mutex; //定义互斥锁
//定义链表结构体
struct Node
{
int number;
struct Node* next;
};
//定义头结点
struct Node* head = NULL;
//当前产品总数
int num = 0;
//生产者线程函数
void* producer(void* arg)
{
while(1)
{
//判断生产者资源是否为0
sem_wait(&semp);
//上锁
pthread_mutex_lock(&mutex);
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); //新节点
newNode->number = rand() % 1000 + 1;
newNode->next = head; //头插法
head = newNode;
num++;
printf("生产者, id:%ld, number:%d, 剩余产品数:%d\n"
, pthread_self(), newNode->number, num);
//解锁
pthread_mutex_unlock(&mutex);
//消费者的资源+1
sem_post(&semc);
sleep(rand() % 3); //把CPU时间片交给其他线程,不然执行太快了看不到效果
}
return NULL;
}
//消费者
void* comsumer(void* arv)
{
while(1)
{
//判断消费者资源是否为0
sem_wait(&semc);
//上锁
pthread_mutex_lock(&mutex);
struct Node* node = head;
head = head->next; //删头
num--;
printf("消费者, id:%ld, number:%d, 剩余产品数:%d\n"
, pthread_self(), node->number, num);
free(node);
//解锁
pthread_mutex_unlock(&mutex);
//消费者资源数+1
sem_post(&semp);
sleep(rand() % 3);
}
return NULL;
}
int main()
{
//初始化互斥锁和信号变量
sem_init(&semp, 0, 10);
sem_init(&semc, 0, 0);
pthread_mutex_init(&mutex, NULL);
//创建线程
pthread_t t1[5], t2[5];
for (int i = 0; i < 5; i++)
{
pthread_create(&t1[i], NULL, producer, NULL);
}
for (int i = 0; i < 5; i++)
{
pthread_create(&t2[i], NULL, comsumer, NULL);
}
//回收线程资源,由于生产者线程和消费者线程都是死循环,主线程被阻塞在这里了
for (int i = 0; i < 5; i++)
{
pthread_join(t1[i], NULL);
pthread_join(t2[i], NULL);
}
//销毁互斥锁和信号变量
pthread_mutex_destroy(&mutex);
sem_destroy(&semp);
sem_destroy(&semc);
return 0;
}
关键问题:
- 两个线程函数对应两个信号量
- 如果将生产者信号量初始化为1,说明总资源数为1,这时候不加锁也能实现线程同步,因为生产者和消费者总是只有一个线程能执行
- 如果生产者信号量的初始值大于1,就需要对临界资源加互斥锁或者读写锁(本例子中加的互斥锁),否则会有多个生产者或消费者线程同时访问临界资源,造成错误
- 如果加了锁,上锁应该在sem_wait之后,解锁应该在sem_post之前,否则会造成死锁