场景
三个生产者和五个消费者通过一个共享缓冲区进行操作,缓冲区用链表进行维护,生产后采用头插法插入,消费也同理。
两种思路
- 条件变量
- 让线程等待某个条件成立,避免忙等待(busy-waiting)。
- 通常和互斥锁(mutex)一起使用,构成 “等待-通知” 机制。
- 信号量
- 控制对共享资源的访问数量(比如限制同时访问的线程数)。
- 可以看作是一个计数器,线程通过 wait(P操作)和 post(V操作)来增减计数。
链表节点定义
//链表维护缓冲区
struct Node{
int data; //数据
struct Node *ptr_next; //指向下一节点的指针
};
1、条件变量思路
- 声明以及初始化
//条件变量声明
pthread_cond_t cond;
//条件变量初始化
pthread_cond_init(&cond,NULL);
- 生产者
void *produce(void *args){
while (1){
pthread_mutex_lock(&mutex); //加锁
struct Node *new_node=(struct Node*)malloc(sizeof(struct Node));
new_node->ptr_next=head;
head=new_node;
new_node->data=rand()%1000;
printf("thread: %ld has product %d in it\n",pthread_self(),new_node->data);
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_signal(&cond); //生产结束后,通知消费者
usleep(1000);
}
return NULL;
}
- 消费者
void *custom(void *args){
while(1){
pthread_mutex_lock(&mutex);
if(head!=NULL){ //有资源时
struct Node *temp=head; //临时结点保存被“消费的”结点
head=head->ptr_next;
printf("thread: %ld has customed %d in it\n",pthread_self(),temp->data);
free(temp);
pthread_mutex_unlock(&mutex);
usleep(1000);
}else{ //没有资源消费者只能等待
pthread_cond_wait(&cond,&mutex); //等待条件
pthread_mutex_unlock(&mutex);
}
}
return NULL;
}
- 销毁条件变量
pthread_cond_destroy(&cond);
2、信号量思路
-
思路总览
-
信号量声明与初始化
sem_t pro_s; //生产者信号量
sem_t cus_s; //消费者信号量
sem_init(&pro_s,0,5);
sem_init(&cus_s,0,0);
- 生产者
//生产
void *produce(void *args){
while (1){
sem_wait(&pro_s); //等待初始空位(5)
pthread_mutex_lock(&mutex); //加锁
struct Node *new_node=(struct Node*)malloc(sizeof(struct Node));
new_node->ptr_next=head;
head=new_node;
new_node->data=rand()%1000;
printf("thread: %ld has product %d in it\n",pthread_self(),new_node->data);
pthread_mutex_unlock(&mutex); //解锁
sem_post(&cus_s); //生产完成后,通知消费者
usleep(1000);
}
return NULL;
}
- 消费者
void *custom(void *args){
while(1){
sem_wait(&cus_s); //等待资源
pthread_mutex_lock(&mutex);
struct Node *temp=head; //临时结点保存被“消费的”结点
head=head->ptr_next;
printf("thread: %ld has customed %d in it\n",pthread_self(),temp->data);
free(temp);
pthread_mutex_unlock(&mutex);
sem_post(&pro_s); //消费结束后通知生产者
usleep(1000);
}
return NULL;
}
条件变量全部实现
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
//互斥锁声明
pthread_mutex_t mutex;
//条件变量声明
pthread_cond_t cond;
//链表维护缓冲区
struct Node{
int data; //数据
struct Node *ptr_next; //指向下一节点的指针
};
struct Node *head=NULL; //头结点
//生产
void *produce(void *args){
while (1){
pthread_mutex_lock(&mutex); //加锁
struct Node *new_node=(struct Node*)malloc(sizeof(struct Node));
new_node->ptr_next=head;
head=new_node;
new_node->data=rand()%1000;
printf("thread: %ld has product %d in it\n",pthread_self(),new_node->data);
pthread_mutex_unlock(&mutex); //解锁
pthread_cond_signal(&cond); //生产结束后,通知消费者
usleep(1000);
}
return NULL;
}
//消费,头删法
void *custom(void *args){
while(1){
pthread_mutex_lock(&mutex);
if(head!=NULL){ //有资源时
struct Node *temp=head; //临时结点保存被“消费的”结点
head=head->ptr_next;
printf("thread: %ld has customed %d in it\n",pthread_self(),temp->data);
free(temp);
pthread_mutex_unlock(&mutex);
usleep(1000);
}else{ //没有资源消费者只能等待
pthread_cond_wait(&cond,&mutex); //等待条件
pthread_mutex_unlock(&mutex);
}
}
return NULL;
}
int main(){
pthread_mutex_init(&mutex,NULL); //互斥锁初始化
pthread_cond_init(&cond,NULL); //条件变量初始化
pthread_t pro_thread[3],cus_thread[5]; //三个生产者,五个消费者
// 分别创建生产者线程
for (int i = 0; i < 3; i++) {
pthread_create(&pro_thread[i], NULL, produce, NULL);
}
// 分别创建消费者线程
for (int j = 0; j < 5; j++) {
pthread_create(&cus_thread[j], NULL, custom, NULL);
}
// 分离所有线程
for (int i = 0; i < 3; i++) {
pthread_detach(pro_thread[i]);
}
for (int j = 0; j < 5; j++) {
pthread_detach(cus_thread[j]);
}
//防止主线程退出,从而引发段错误
while(1) {
sleep(1);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_exit(NULL); //退出主线程
return 0;
}
信号量全部实现
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
//互斥锁声明
pthread_mutex_t mutex;
//信号量声明
sem_t pro_s; //生产者信号量
sem_t cus_s; //消费者信号量
//链表维护缓冲区
struct Node{
int data; //数据
struct Node *ptr_next; //指向下一节点的指针
};
struct Node *head=NULL; //头结点
//生产
void *produce(void *args){
while (1){
sem_wait(&pro_s); //等待初始空位(5)
pthread_mutex_lock(&mutex); //加锁
struct Node *new_node=(struct Node*)malloc(sizeof(struct Node));
new_node->ptr_next=head;
head=new_node;
new_node->data=rand()%1000;
printf("thread: %ld has product %d in it\n",pthread_self(),new_node->data);
pthread_mutex_unlock(&mutex); //解锁
sem_post(&cus_s); //生产完成后,通知消费者
usleep(1000);
}
return NULL;
}
//消费,头删法
void *custom(void *args){
while(1){
sem_wait(&cus_s); //等待资源
pthread_mutex_lock(&mutex);
struct Node *temp=head; //临时结点保存被“消费的”结点
head=head->ptr_next;
printf("thread: %ld has customed %d in it\n",pthread_self(),temp->data);
free(temp);
pthread_mutex_unlock(&mutex);
sem_post(&pro_s); //消费结束后通知生产者
usleep(1000);
}
return NULL;
}
int main(){
pthread_mutex_init(&mutex,NULL); //互斥锁初始化
sem_init(&pro_s,0,5);
sem_init(&cus_s,0,0);
pthread_t pro_thread[3],cus_thread[5]; //三个生产者,五个消费者
// 分别创建生产者线程
for (int i = 0; i < 3; i++) {
pthread_create(&pro_thread[i], NULL, produce, NULL);
}
// 分别创建消费者线程
for (int j = 0; j < 5; j++) {
pthread_create(&cus_thread[j], NULL, custom, NULL);
}
// 分离所有线程
for (int i = 0; i < 3; i++) {
pthread_detach(pro_thread[i]);
}
for (int j = 0; j < 5; j++) {
pthread_detach(cus_thread[j]);
}
//防止主线程退出,从而引发段错误
while(1) {
sleep(1);
}
pthread_mutex_destroy(&mutex);
pthread_exit(NULL); //退出主线程
return 0;
}