生产者消费者模型(条件变量)

三种关系:互斥,同步,互斥和同步
两类角色:生产者,消费者(线程)
一个交易场所:生产者消费者共享的区域

卖苹果的模型

  • dish上面只有一个苹果
  • 买家必须要等卖家把苹果放到dish上才可以去买苹果。
  • 卖家必须等待买家把苹果买走才可以生产苹果
  • pthread_mutex_lock(&mutex); 和pthread_mutex_unlock(&mutex); 成对出现,里面的操作为一个原子操作
  • pthread_cond_wait(&empty,&mutex);内部有一个加锁解锁操作
  • 过程详解
    • 苹果为0
    • 初始化时苹果为0,买家在pthread_cond_wait(&empty,&mutex); 开始等待,卖家不进入while循环,生产苹果后发出pthread_cond_signal(&empty);让正在因dish上苹果为0的买家停止等待pthread_cond_wait(&empty,&mutex);
    • 苹果为1
    • 当一个卖家进入pthread_mutex_lock(&mutex); 但是发现苹果为1时,就在while循环处等待pthread_cond_wait(&empty,&mutex);,直到买家发出信号 pthread_cond_signal(&full);卖家停止等待,此时苹果为0,跳出while循环,开始生产苹果。生产苹果后发出pthread_cond_signal(&empty);让正在因dish上苹果为0的买家停止等待pthread_cond_wait(&empty,&mutex); 这样这个过程就结束了
      *
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>int dish = 0;
pthread_cond_t full;
pthread_cond_t empty;
pthread_mutex_t mutex;void * consumer(void * arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex);//上锁while(dish == 0){//买家发现没有苹果开始等待pthread_cond_wait(&empty,&mutex);}usleep(100000);dish = 0;printf("consumer %d get an apple!!\n", id);//给卖家发送信号pthread_cond_signal(&full);pthread_mutex_unlock(&mutex);//解锁}return NULL;
}void * product(void *arg)
{int id = (int)arg;while(1){pthread_mutex_lock(&mutex);    while(dish == 1){pthread_cond_wait(&full,&mutex);}dish =1;printf("producer %d put an apple!!\n", id);      pthread_cond_signal(&empty);pthread_mutex_unlock(&mutex);}return NULL;
}int main()
{pthread_t tid;int set ;//初始化pthread_cond_init(&full,NULL);pthread_cond_init(&empty,NULL);pthread_mutex_init(&mutex,NULL);//四个卖家生产苹果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,product,(void *)i);}//四个买家买苹果for(int i = 0;i<4;i++){pthread_create(&tid,NULL,consumer,(void *)i);}//等待thread标识的线程终止,防止僵尸进程产生pthread_join(tid,NULL);//销毁所有资源pthread_cond_destroy(&full);pthread_cond_destroy(&empty);pthread_mutex_destroy(&mutex);
}

如果对于互斥量含义尚不清楚,建议阅读Linux/UNIX系统编程手册

pthread_mutex_t
pthread_mutex_init
pthread_mutex_lock
pthread_mutex_unlock
pthread_mutex_destroy

模型采取Linux/UNIX系统编程手册
这个模型很好,也把概念讲清楚了,加了中文注释

生产者

s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++;        /*这是一个原子操作 */s = pthread_mutex_unlock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond);         /* 唤醒消费者 */
if (s != 0)errExitEN(s, "pthread_cond_signal");

消费者

s = pthread_mutex_lock(&mtx);
if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0){           s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");
}

完整代码

#include <time.h>
#include <pthread.h>
#include "tlpi_hdr.h"static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;static int avail = 0;static void *
threadFunc(void *arg)
{int cnt = atoi((char *) arg);int s, j;for (j = 0; j < cnt; j++) {sleep(1);/* Code to produce a unit omitted */s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");avail++;        /* Let consumer know another unit is available */s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");s = pthread_cond_signal(&cond);         /* Wake sleeping consumer */if (s != 0)errExitEN(s, "pthread_cond_signal");}return NULL;
}int
main(int argc, char *argv[])
{pthread_t tid;int s, j;int totRequired;            /* Total number of units that all threadswill produce */int numConsumed;            /* Total units so far consumed */Boolean done;time_t t;t = time(NULL);/* Create all threads */totRequired = 0;for (j = 1; j < argc; j++) {totRequired += atoi(argv[j]);s = pthread_create(&tid, NULL, threadFunc, argv[j]);if (s != 0)errExitEN(s, "pthread_create");}/* Loop to consume available units */numConsumed = 0;done = FALSE;for (;;) {s = pthread_mutex_lock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_lock");while (avail == 0) {            /* Wait for something to consume */s = pthread_cond_wait(&cond, &mtx);if (s != 0)errExitEN(s, "pthread_cond_wait");}/* At this point, 'mtx' is locked... */while (avail > 0) {             /* Consume all available units *//* Do something with produced unit */numConsumed ++;avail--;printf("T=%ld: numConsumed=%d\n", (long) (time(NULL) - t),numConsumed);done = numConsumed >= totRequired;}s = pthread_mutex_unlock(&mtx);if (s != 0)errExitEN(s, "pthread_mutex_unlock");if (done)break;/* Perhaps do other work here that does not require mutex lock */}exit(EXIT_SUCCESS);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382710.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux之信号

信号&#xff1a;在生活中&#xff0c;我们遇到过不同种类的信号&#xff0c;比如&#xff1a;&#xff08;交通信号&#xff0c;乃至某个人的表情&#xff0c;动作等带给你不同的信号&#xff09;然而&#xff0c;在我们的linux下&#xff0c;我们最熟悉的就是&#xff0c;当遇…

视频解析有感,在解析 iqiyi与qq视频的时候,记录一些发现

最近对iqiyi与qq视频解析发现&#xff0c;两个网站的解析流程&#xff0c;尤其是反解析措施 各有特点&#xff0c;简单记录一下 先说iqiyi&#xff0c; 浏览器模拟移动端可以拿到视频的mp4链接&#xff0c;这个不多说。 iqiyiPC端浏览器获取 ts过程&#xff1a; a.iqiyi一次性…

C语言atoi函数的用法

#include < stdlib.h > int atoi(const char *nptr);用法&#xff1a;将字符串里的数字字符转化为整形数。返回整形值。 注意&#xff1a;转化时跳过前面的空格字符&#xff0c;直到遇上数字或正负符号才开始做转换&#xff0c;而再遇到非数字或字符串结束时(’/0’)才…

[Linux]继续探究mysleep函数(竞态条件)

之前我们探究过mysleep的简单用法&#xff0c;我们实现的代码是这样的&#xff1a; #include<stdio.h> #include<signal.h>void myhandler(int sig) {}unsigned int mysleep(unsigned int timeout) {struct sigaction act,oact;act.sa_handler myhandler;sigempt…

C语言的atoi和C++的to_string

to_stringint to string将其他型转换成字符串型atoiascii to integer是把字符串转换成整型数的一个函数 to_string #include <iostream> // std::cout #include <string> // std::string, std::to_stringint main () {std::string perfect std::to_string…

ubuntu 升级python3.5到python3.7,并升级pip3

1, 下载python3.7.tgz 文件&#xff0c;解压&#xff0c; 2. 编译安装 3. 删除 /usr/bin 目录下的 pip3, python3 4. 建立新的软连接&#xff1a; #添加python3的软链接ln -s /usr/local/python3/bin/python3.7 /usr/bin/python3#添加 pip3 的软链接ln -s /usr/local/python3/b…

[Linux]死锁

死锁是指多个进程在运行过程中因争夺资源而造成的一种僵局&#xff0c;当进程处于这种僵持状态时&#xff0c;若无外力作用&#xff0c;它们都将无法再向前推进。之前信号量的时候我们知道&#xff0c;如果多个进程等待&#xff0c;主要体现在占有锁的问题上。死锁也可以被定义…

Python安装第三方模块总结 转载的

转自 https://www.jellythink.com/archives/541

[C++]vector创建二维数组

c.resize(n);将c重置为大小为n个元素向量&#xff0c;如果n比原来的元素多&#xff0c;则多出的元素常被初始化为0//节选《面向对象的程序设计》杜茂青 int N5, M6; vector<vector<int> > Matrix(N); for(int i 0; i< Matrix.size(); i){ Matrix[i].resize(M…

[Linux]线程安全和可重入函数

线程安全&#xff1a;一个函数被称为线程安全的&#xff0c;当且仅当被多个并发进程反复调用时&#xff0c;它会一直产生正确的结果。如果一个函数不是线程安全的&#xff0c;我们就说它是线程不安全的。 重入&#xff1a;函数被不同的控制流程调用,有可能在第一次调用还没返回…

[Linux]信号量

信号量是一个计数器&#xff0c;用于为多个进程提供对共享数据对象的访问。 在信号量上只有三种操作可以进行&#xff0c;初始化、递增和增加&#xff0c;这三种操作都是原子操作。递减操作可以用于阻塞一个进程&#xff0c;增加操作用于解除阻塞一个进程。 为了获得共享资源…

Linux VIM 程序中有游离的‘\357’ ‘\274’错误

gcc date.cpp -o date -lstdc date.cpp:18:20: 错误&#xff1a;程序中有游离的‘\357’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:21: 错误&#xff1a;程序中有游离的‘\274’date.Showdata()&#xfffd;&#xfffd;&#xfffd;^ date.cpp:18:22…

[Linux]关于SIGCHLD

之前我们就学过&#xff0c;关于wait和waitpid来处理僵尸进程&#xff0c;父进程等待子进程结束后自己才退出&#xff0c;这样的方法有俩种方式&#xff0c;一种是父进程死死的等子进程退出&#xff0c;也就是使用阻塞的方式等待子进程退出&#xff0c;另一种方式是通过非阻塞的…

C语言思维导图

本人能力有限&#xff0c;知识点难免概括不全&#xff0c;如有错误欢迎指正

转载一篇关于curl的文章

转载一篇关于curl的文章 http://www.360doc.com/content/16/0107/15/18578054_526158476.shtml

[Linux]vi/vim下添加多行注释和取消注释

添加注释&#xff08;Centos&#xff09;&#xff1a; 在命令行模式下按ctrlV进入 visual block模式&#xff08;可视化模式&#xff09; 选中你需要注释的行&#xff0c;再按大写的I&#xff0c;输入//&#xff0c;最后按俩下esc即可。 如果想让前进tab个位&#xff0c;则可在…

pthread和互斥量条件变量函数意义速查表

数据类型 pthread_t 线程 互斥量和条件变量

[Linux]共享内存

共享内存是UNIX提供的进程间通信手段中速度最快的一种&#xff0c;也是最快的IPC形式。为什么是最快的呢&#xff0c;因为数据不需要在客户进程和服务器进程之间复制&#xff0c;所以是最快的一种IPC。这是虚存中由多个进程共享的一个公共内存块。 两个不同进程A、B共享内存的…

僵尸进程的产生,危害和解决方案

概念 僵死状态&#xff08;Zombies&#xff09;是一个比较特殊的状态。 当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。僵尸进程会以终止状态保持在进程表中&#xff0c;并且会一直在等待父进程读取退出状态代码。所以&#xff0c;只要子进程退出&…

CString string 转换

https://www.cnblogs.com/HappyEDay/p/7016162.html