生产者消费者问题,又有界缓冲区问题。两个进程共享一个一个公共的固定大小的缓冲区。其中一个是生产者,将信息放入缓冲区,另一个是消费者,从缓冲区中取信息。

问题的关键在于缓冲区已满,而此时生产者还想往其中放入一个新的数据的情况。其解决办法是让生产者睡眠,待消费者从缓冲区中取出一个或多个数据时再唤醒它,同样的, 当消费者试图从缓冲区中取数据而发现缓冲区空时,消费者就睡眠,直到消费者向其中放一些数据后再将其唤醒。

上述方法可以用互斥量解决,程序代码:

 #include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h> //消费者进程
void *thread_consumer(void *ptr);
//生产者进程
void *thread_producer(void *ptr); #define MAX 100000 /*生产者需要生产的数量*/
pthread_mutex_t the_mutex; /*互斥量*/
pthread_cond_t condc,condp;/*生产者和消费者的线程条件变量*/ //初始时缓冲区中没有数据
int buffer=; int buffer_max=;/*用于记录缓冲区最多被用了多少*/ #define BUFFER_SIZE 10000 /*缓冲区大小*/ /*消费者线程*/
void *thread_consumer(void *arg)
{
int i;
//消费完指定数目 退出线程
for(i=;i<MAX;i++)
{
//互斥量加锁,线程同步
pthread_mutex_lock(&the_mutex);
/*缓冲区空 该进程睡眠 睡眠时pthread_cond_wait函数会对互斥量the_mutex解锁,这样生产者线程可以正常工作*/
while(buffer==)
{
pthread_cond_wait(&condc,&the_mutex);
}
//缓冲区非空 此时pthread_cond_wait又会对互斥量再次加锁
--buffer; //消耗一个元素
printf("consume an element, buffer=%d\n",buffer); //打印缓冲区中剩余元素
//如果缓冲区中元素个数为0 唤醒生产者线程
if(buffer==)
{
pthread_cond_signal(&condp);
}
//释放互斥量
pthread_mutex_unlock(&the_mutex);
}
pthread_exit(NULL);
} /*生产者线程*/
void *thread_producer(void *ptr)
{
int i;
//消费完指定数目 退出线程
for(i=;i<MAX;i++)
{
//互斥量加锁,线程同步
pthread_mutex_lock(&the_mutex);
//缓冲区满, 该进程睡眠 睡眠时pthread_cond_wait函数会对互斥量the_mutex解锁,这样消费者线程可以正常工作*/
while(buffer==BUFFER_SIZE)
{
pthread_cond_wait(&condp,&the_mutex);
}
// 缓冲区未满时 此时pthread_cond_wait又会对互斥量再次加锁
++buffer;//生产者增加一个数据
/*记录缓冲区最大的数据个数*/
if(buffer>buffer_max)
buffer_max=buffer;
printf("produce an element, buffer=%d\n",buffer);
//如果缓冲区中元素个数大于0 唤醒消费者线程
if(buffer>)
{
pthread_cond_signal(&condc);
}
//释放互斥量
pthread_mutex_unlock(&the_mutex);
}
} int main()
{
pthread_t pro,con;
//初始化互斥量
pthread_mutex_init(&the_mutex,);
//初始化线程条件变量
pthread_cond_init(&condc,);
pthread_cond_init(&condp,);
//创建生产者、消费者两个线程
pthread_create(&con,NULL,thread_consumer,NULL);
pthread_create(&pro,NULL,thread_producer,NULL);
//等待两个线程结束
pthread_join(pro,);
pthread_join(con,);
//清除变量
pthread_cond_destroy(&condc);
pthread_cond_destroy(&condp);
pthread_mutex_destroy(&the_mutex);
printf("buffer_max=%d",buffer_max);
}

在linux下运行时,可以看到两个线程交替运行,为了看到缓冲区最大能被添加到多少,我把缓冲区大小设置的很大,这样每次运行程序,打印的缓冲区的最大数都是不一样的,这跟实际的线程调度有关。

科学家就餐问题:

问题描述:假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。用下面的图描述很现实

问题解决:每个哲学家对应一个线程,程序中定义一个互斥量,对于每个线程进行访问其他哲学家状态时(关键代码)用互斥量进行加锁,这样也就避免了死锁的产生,访问到该哲学家处于饥饿时,同时旁边两位科学家并未处于进餐状态时,他就拿起左右两边的叉子进行吃饭,吃饭一段时间后,就放下叉子进行思考,思考一段时间后处于饥饿状态,重新开始试图拿起叉子吃饭,代码如下:

#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<time.h>
#define N 5 //哲学家数量 #define LEFT(i) (i+N-1)%N //左手边哲学家编号
#define RIGHT(i) (i+1)%N //右手边哲家编号 #define HUNGRY 0 //饥饿
#define THINKING 1 //思考
#define EATING 2 //吃饭 #define U_SECOND 1000000 //1秒对应的微秒数
pthread_mutex_t mutex; //互斥量 int state[N]; //记录每个哲学家状态
//每个哲学家的思考时间,吃饭时间,思考开始时间,吃饭开始时间
clock_t thinking_time[N], eating_time[N], start_eating_time[N], start_thinking_time[N];
//线程函数
void *thread_function(void *arg); int main()
{
pthread_mutex_init(&mutex, NULL); pthread_t a,b,c,d,e;
//为每一个哲学家开启一个线程,传递哲学家编号
pthread_create(&a,NULL,thread_function,"");
pthread_create(&b,NULL,thread_function,"");
pthread_create(&c,NULL,thread_function,"");
pthread_create(&d,NULL,thread_function,"");
pthread_create(&e,NULL,thread_function,"");
//初始化随机数种子
srand((unsigned int)(time(NULL)));
while()
{
;
}
} void *thread_function(void *arg)
{
char *a = (char *)arg;
int num = a[] - ''; //根据传递参数获取哲学家编号
int rand_time;
while()
{
//关键代码加锁
pthread_mutex_lock(&mutex);
//如果该哲学家处于饥饿 并且 左右两位哲学家都没有在吃饭 就拿起叉子吃饭
if(state[num] == HUNGRY && state[LEFT(num)] != EATING && state[RIGHT(num)] != EATING)
{
state[num] = EATING;
start_eating_time[num] = clock(); //记录开始吃饭时间
eating_time[num] = (rand() % + ) * U_SECOND; //随机生成吃饭时间
//输出状态
printf("state: %d %d %d %d %d\n",state[],state[],state[],state[],state[]);
//printf("%d is eating\n",num);
}
else if(state[num] == EATING)
{
//吃饭时间已到 ,开始思考
if(clock() - start_eating_time[num] >= eating_time[num]) //
{
state[num] = THINKING;
//printf("%d is thinking\n",num);
printf("state: %d %d %d %d %d\n",state[],state[],state[],state[],state[]);
start_thinking_time[num] = clock(); //记录开始思考时间
thinking_time[num] = (rand() % + ) * U_SECOND; //随机生成思考时间
}
}
else if(state[num] == THINKING)
{
//思考一定时间后,哲学家饿了,需要吃饭
if(clock() - start_thinking_time[num] >= thinking_time[num])
{
state[num] = HUNGRY;
printf("state: %d %d %d %d %d\n",state[],state[],state[],state[],state[]);
// printf("%d is hungry\n",num);
}
}
pthread_mutex_unlock(&mutex);
}
}

linux下多线程互斥量实现生产者--消费者问题和哲学家就餐问题的更多相关文章

  1. Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  2. Linux驱动多线程 - 互斥量

    1.内核多线程相关内容 1.1 头文件#include <linux/kthread.h> 1.2 定义/初始化变量 struct mutex SPI_work; /*定义互斥体*/ mu ...

  3. 【Linux】Mutex互斥量线程同步的例子

    0.互斥量  Windows下的互斥量 是个内核对象,每次WaitForSingleObject和ReleaseMutex时都会检查当前线程ID和占有互斥量的线程ID是否一致. 当多次Wait**时就 ...

  4. OS: 读者写者问题(写者优先+LINUX+多线程+互斥量+代码)(转)

    一. 引子 最近想自己写个简单的 WEB SERVER ,为了先练练手,熟悉下在LINUX系统使用基本的进程.线程.互斥等,就拿以前学过的 OS 问题开开刀啦.记得当年学读者写者问题,尤其是写者优先的 ...

  5. POSIX信号量与互斥锁实现生产者消费者模型

    posix信号量 Link with -lpthread. sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量 sem_t *sem_o ...

  6. [转载]解决linux 下多线程错误 undefined reference to `sem_init'

    转自:https://blog.csdn.net/yzycqu/article/details/7396498?utm_source=copy 解决linux 下多线程错误 undefined ref ...

  7. Linux 多线程互斥量互斥

    同步 同一个进程中的多个线程共享所在进程的内存资源,当多个线程在同一时刻同时访问同一种共享资源时,需要相互协调,以避免出现数据的不一致和覆盖等问题,线程之间的协调和通信的就叫做线程的同步问题, 线程同 ...

  8. posix 匿名信号量与互斥锁 示例生产者--消费者问题

    一.posix 信号量 信号量的概念参见这里.前面也讲过system v 信号量,现在来说说posix 信号量. system v 信号量只能用于进程间同步,而posix 信号量除了可以进程间同步,还 ...

  9. Linux 进程间通信(包含一个经典的生产者消费者实例代码)

    前言:编写多进程程序时,有时不可避免的需要在多个进程之间传递数据,我们知道,进程的用户的地址空间是独立,父进程中对数据的修改并不会反映到子进程中,但内核是共享的,大多数进程间通信方式都是在内核中建立一 ...

随机推荐

  1. spring boot高性能实现二维码扫码登录(下)——订阅与发布机制版

     前言 基于之前两篇(<spring boot高性能实现二维码扫码登录(上)——单服务器版>和<spring boot高性能实现二维码扫码登录(中)——Redis版>)的基础, ...

  2. 【Python】 基于秘钥的对称加密

    [Crypto] 关于用python进行信息的加密,类似的解决方案有很多比如用base64编码进行encode,再或者是hashlib来进行hash.但是还缺少一种明明场景很简单的解决方案,就是把利用 ...

  3. 设计模式 --> (3)策略模式

    策略模式 策略模式是指定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化.也就是说这些算法所完成的功能一样,对外的接口一样,只是各自实现上存在差异. ...

  4. Vue探索历程(一)

    使用vue.js原文介绍:Vue.js是一个构建数据驱动的web界面库.Vue.js的目标是通过尽可能简单的API实现响应式数据绑定和组合的视图组件.vue.js上手非常简单,先看看几个例子: 例一: ...

  5. Alpha冲刺No.10

    一.站立式会议 我们的阿尔法冲刺也基本宣告血崩,虽然很多功能已经实现,但是并没有串联在一起,好在这周不需要上课,我们也能好好睡一觉 实现手机的定位系统 细化界面设计 解决数据库和软件交互的一些问题 二 ...

  6. 20162330 第十二周 蓝墨云班课 hash

    题目要求 利用除留余数法为下列关键字集合的存储设计hash函数,并画出分别用开放寻址法和拉链法解决冲突得到的空间存储状态(散列因子取0.75) 关键字集合:85,75,57,60,65,(你的8位学号 ...

  7. 学号:201621123032 《Java程序设计》第7周学习总结

    1:本周学习总结 1.1:思维导图:Java图形界面总结 2:书面作业 2.1: GUI中的事件处理 2.1.1: 写出事件处理模型中最重要的几个关键词 事件:如鼠标单击,滑动,输入汉字等. 事件源: ...

  8. 团队作业4——第一次项目冲刺(Alpha版本)11.16

    a. 提供当天站立式会议照片一张 举行站立式会议,讨论项目安排: 整理各自的任务汇报: 全分享遇到的困难一起讨论: 讨论接下来的计划: b. 每个人的工作 (有work item 的ID) 1.前两天 ...

  9. NetFPGA-1G-CML点亮 LED

    前言 用vivado建立工程的时候选择的型号为:XC7K325tffg676-1 在以下代码文件中,仿真与设计都没有问题.在xdc文件中的时钟约束与锁相环配置中还存在问题,没有寻找到解决办法 使用手册 ...

  10. Web前端性能分析

    Web前端性能通常上代表着一个完全意义上的用户响应时间,包含从开始解析HTML文件到最后渲染完成开始的整个过程,但不包括在输入url之后与服务器的交互阶段.下面是整个过程的各个步骤: 开始解析html ...