生产者与消费者模型
生产者:产生数据的进程或线程
消费者:使用数据的进程或线程
仓库:隔离生产者与消费者的缓冲区,与二者直连相比,避免了相互等待,提高了运行效率
问题1:生产快于消费,仓库满,生产者撑死。
生产者降低生产,通知消费,生产者线程进入睡眠叫醒睡眠的消费者线程
问题2:消费快于生产,仓库空,消费者饿死。
消费者降低消费,通知生产 消费者线程进入睡眠,叫醒睡眠的生产者线程
条件变量
可以让线程睡进去或者醒过来的一个容器,要与互斥锁配合使用
pthread_cond_t
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化条件变量
int pthread_cond_signal(pthread_cond_t *cond);
功能:叫醒条件变量中的一个线程,并重新加锁互斥量,如果不能加,则进入阻塞状态
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:叫醒条件变量中的所有线程,并重新加锁互斥量,如果不能加,则进入阻塞状态
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
功能:让当前线程睡入条件变量,并解锁一个互斥量
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
功能:让当前线睡入程条件变量一段时间并解锁互斥量,时间到后自动醒来并加锁互斥量
int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁条件变量
介绍完基础概念和函数直接上代码~
栈实现消费者生产者模型
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
// 仓库容量
#define STORE_SIZE (20)
// 仓库
char store[STORE_SIZE];
// 数量
size_t store_cnt = 0;
pthread_mutex_t lock;
pthread_cond_t cond_empty;
pthread_cond_t cond_full;
void show_store(const char* who,const char* act,char data)
{
printf("[");
for(int i=0; i<store_cnt; i++)
{
printf("%c",store[i]);
}
printf("]%s%c : %s\n",act,data,who);
}
void* prun(void* arg)//生产者
{
for(;;)
{
// 加锁
pthread_mutex_lock(&lock);
while(store_cnt >= STORE_SIZE)
{
// 此时仓库已满,生产者睡入仓库满的条件变量
pthread_cond_wait(&cond_full,&lock);
}
// 生产数据
char data = rand() % 26 + 'A';
show_store("生产者","<-",data);
store[store_cnt++] = data;
usleep(rand()%30000);
// 解锁
pthread_mutex_unlock(&lock);
// 叫醒所有睡入仓库空条件变量的线程
pthread_cond_broadcast(&cond_empty);
}
}
void* crun(void* arg)//消费者
{
for(;;)
{
// 加锁
pthread_mutex_lock(&lock);
while(0 >= store_cnt)
{
// 此时仓库为空,生产者睡入仓库空的条件变量
pthread_cond_wait(&cond_empty,&lock);
}
// 消费数据
char data = store[--store_cnt];
show_store("消费者","->",data);
usleep(rand()%30000);
// 解锁
pthread_mutex_unlock(&lock);
// 叫醒所有睡入仓库满条件变量的线程
pthread_cond_broadcast(&cond_full);
}
}
int main()
{
srand(time(NULL));
// 初始化互斥量与条件变量
pthread_mutex_init(&lock,NULL);
pthread_cond_init(&cond_empty,NULL);
pthread_cond_init(&cond_full,NULL);
pthread_t tid[10];
//创建生产者线程
for(int i=0; i<5; i++)
{
if(i%2)
pthread_create(&tid[i],NULL,prun,NULL);
else
pthread_create(&tid[i],NULL,crun,NULL);
}
// 等待所有线程结束
for(int i=0; i<10; i++)
{
pthread_join(tid[i],NULL);
}
}
队列实现消费者生产者模型
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
// 仓库容量
#define STORE_SIZE (20)
// 仓库
char store[STORE_SIZE];
// 队头和队尾
int front = 0 , rear = 0;
pthread_mutex_t flock;
pthread_mutex_t rlock;
pthread_cond_t cond_empty;
pthread_cond_t cond_full;
void show_store(const char* who,const char* act,char data)
{
printf("[");
for(int i=front; i!=rear; i=(i+1)%STORE_SIZE)
{
printf("%c",store[i]);
}
printf("]%s%c : %s\n",act,data,who);
}
void* prun(void* arg)
{
for(;;)
{
// 加锁
pthread_mutex_lock(&flock);
while((rear+1)%STORE_SIZE == front)
{
// 此时仓库已满,生产者睡入仓库满的条件变量
pthread_cond_wait(&cond_full,&flock);
}
// 生产数据
char data = rand() % 26 + 'A';
show_store("生产者","<-",data);
store[rear++] = data;
rear %= STORE_SIZE;
usleep(rand()%500000);
// 叫醒所有睡入仓库空条件变量的线程
pthread_cond_broadcast(&cond_empty);
// 解锁
pthread_mutex_unlock(&flock);
}
}
void* crun(void* arg)
{
for(;;)
{
// 加锁
pthread_mutex_lock(&rlock);
while(front == rear)
{
// 此时仓库为空,生产者睡入仓库空的条件变量
pthread_cond_wait(&cond_empty,&rlock);
}
// 消费数据
char data = store[front++];
front %= STORE_SIZE;
show_store("消费者","->",data);
usleep(rand()%500000);
// 叫醒所有睡入仓库满条件变量的线程
pthread_cond_broadcast(&cond_full);
// 解锁
pthread_mutex_unlock(&rlock);
}
}
int main()
{
srand(time(NULL));
// 初始化互斥量与条件变量
pthread_mutex_init(&flock,NULL);
pthread_mutex_init(&rlock,NULL);
pthread_cond_init(&cond_empty,NULL);
pthread_cond_init(&cond_full,NULL);
pthread_t tid[10];
//创建生产者线程
for(int i=0; i<10; i++)
{
if(i%2)
pthread_create(&tid[i],NULL,prun,NULL);
else
pthread_create(&tid[i],NULL,crun,NULL);
}
// 等待所有线程结束
for(int i=0; i<10; i++)
{
pthread_join(tid[i],NULL);
}
}