linux下互斥锁实现的简单的生产者消费者问题

2023-05-16

这个程序实现的功能很简单,也算是入门linux下的多线程编程了吧~

其创造了两个生产者和一个消费者,两个生产者通过互斥锁实现同步,往缓冲区里放入数据,数据的值和其下标值一样,方便消费者的检验

消费者等到生产者放完数据后,从缓冲区中取出数据,并进行检验,看是否有出现差错,没有的话即实现了同步操作

/* include main */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define	MAXNITEMS 		10      //缓冲区大小为10
/*
	两个生产者,实现它们之间的同步  
	缓冲区内第一个位置放1,第二个位置放2这种
	一个消费者,检验其是否出错
*/

struct 
{
	pthread_mutex_t lock;
	int key;
	int value;
	int buff[MAXNITEMS];
}shared = {
	PTHREAD_MUTEX_INITIALIZER
};

//这样对结构体初始化

void * create_producer1()
{
	for(;;)
	{
		pthread_mutex_lock(&shared.lock);
		if(shared.key >= MAXNITEMS)
		{
			pthread_mutex_unlock(&shared.lock);
			printf("producer1: my function is over~\n"); 
			pthread_exit(NULL);

		}
		shared.buff[shared.key] = shared.value;
		printf("producer1 have put the data: %d\n",shared.value);
		shared.key ++;
		shared.value ++;
		pthread_mutex_unlock(&shared.lock);

	}

}


void * create_producer2()
{

	for(;;)
	{
		pthread_mutex_lock(&shared.lock);
		if(shared.key >= MAXNITEMS)
		{
			pthread_mutex_unlock(&shared.lock);
			printf("producer2: my function is over~\n");
			pthread_exit(NULL);

		}
		shared.buff[shared.key] = shared.value;
		printf("producer2 have put the data: %d\n",shared.value);
		shared.key ++;
		shared.value ++;
		pthread_mutex_unlock(&shared.lock);

	}

	
}

void * create_consumer()
{

	for(int i = 0;i < 10;i++)
	{
		if(shared.buff[i] != i)
		{
			printf("buff[%d] = %d was wrong!\n", i , shared.buff[i]);
			
		}
	}


	printf("All have scanned!\n");
	return (NULL);
}



int main(int argc, char const *argv[])
{
	pthread_t tid1,tid2;
	pthread_t consumer_tid;



	printf("I will create two producers and one consumers\n");

	if(pthread_create(&tid1,NULL,create_producer1,NULL) != 0)
		printf("create producer1 failed!\n");
	else
		printf("producer1 has been create!\n");



	if(pthread_create(&tid2,NULL,create_producer2,NULL) != 0)
		printf("create producer2 failed!\n");
	else
		printf("producer2 has been create!\n");

//等待生产者线程结束
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	if(pthread_create(&consumer_tid,NULL,create_consumer,NULL) != 0)
		printf("create consumer failed!\n");
	else
		printf("consumer has been create and begin check out the buff...\n");


	pthread_join(consumer_tid,NULL);


	return 0;
}

运行截图:

生产者消费者1.0

实现进阶:
我们上一个实现中,规定了当生产者往缓冲区里放完数据后,消费者才去检验,所以就不用考虑生产者和消费者之间的同步问题。这次我们让生产者和消费者一起产生,然后让消费者等待生产者放入其想要监测的数据,即加上这么一段等待的代码

void consumer_wait(int i)
{
	for(;;)
	{
		pthread_mutex_lock(&shared.lock);

		if (i < shared.key)
		{
			pthread_mutex_unlock(&shared.lock);
			return;
		}

		pthread_mutex_unlock(&shared.lock);
	}

}

消费者的代码改为如下:

void * create_consumer()
{

	for(int i = 0;i < 10;i++)
	{
		consumer_wait(i);
		if(shared.buff[i] != i)
		{
			printf("buff[%d] = %d was wrong!\n", i , shared.buff[i]);
			
		}
	}


	printf("All have scanned!\n");
	return (NULL);
}

实现进阶二:

由于上一个实现中,当消费者在等待生产者的时候,它是一遍一遍的轮询,这样很消耗计算机内存资源,我们为了更高效一点,引入信号量。

linux中每一个信号量都关联一个互斥锁,所以我们建立两个结构体,一个存放信号量和互斥锁,还又信号量判断nready,nready=0则消费者阻塞,nready=1则消费者接触堵塞。,一个结构体存放下一个要放入缓冲区下标,还有数值,还有防止冲突的互斥锁。

两个结构体:其自动初始化,也可以手动初始化
struct 
{
	pthread_mutex_t lock;
	int key;
	int value;
}put = {
	PTHREAD_MUTEX_INITIALIZER
};

//通过信号量来控制消息的传递  每一个信号量关联着一个互斥锁
struct {

	pthread_mutex_t mutex;
	pthread_cond_t cond;
	int nready;
} nready = {
	PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER
};

全部代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define	MAXNITEMS 		10      //缓冲区大小为10
/*
	两个生产者,实现它们之间的同步  
	缓冲区内第一个位置放1,第二个位置放2这种
	一个消费者,检验其是否出错
	生产者消费者一起创建 还要保证生产者和消费者之间的同步
	还要防止再期待的条件尚未达到的时候不断轮询造成资源浪费,所以要有信号量
*/

int buff[MAXNITEMS];


struct 
{
	pthread_mutex_t lock;
	int key;
	int value;
}put = {
	PTHREAD_MUTEX_INITIALIZER
};

//通过信号量来控制消息的传递  每一个信号量关联着一个互斥锁
struct {

	pthread_mutex_t mutex;
	pthread_cond_t cond;
	int nready;
} nready = {
	PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER
};

//这样对结构体初始化

//都要加上shared前缀,不要忘了!!!
//还忘记写循环了,没有循环放元素

void * create_producer1()
{
	for(;;)
	{
		pthread_mutex_lock(&put.lock);
		if(put.key >= MAXNITEMS)
		{
			pthread_mutex_unlock(&put.lock);//这里为shared.lock还要加&符号
			printf("producer1: my function is over~\n"); 
			pthread_exit(NULL);

		}
		buff[put.key] = put.value;
		printf("producer1 have put the data: %d\n",put.value);
		put.key ++;
		put.value ++;
		pthread_mutex_unlock(&put.lock);

		pthread_mutex_lock(&nready.mutex);
		if(nready.nready == 0)
			pthread_cond_signal(&nready.cond);
		nready.nready++;
		pthread_mutex_unlock(&nready.mutex);

	}

}


void * create_producer2()
{

	for(;;)
	{
		pthread_mutex_lock(&put.lock);
		if(put.key >= MAXNITEMS)
		{
			pthread_mutex_unlock(&put.lock);//这里为shared.lock还要加&符号
			printf("producer2: my function is over~\n"); 
			pthread_exit(NULL);

		}
		buff[put.key] = put.value;
		printf("producer2 have put the data: %d\n",put.value);
		put.key ++;
		put.value ++;
		pthread_mutex_unlock(&put.lock);

		pthread_mutex_lock(&nready.mutex);
		if(nready.nready == 0)
			pthread_cond_signal(&nready.cond);
		nready.nready++;
		pthread_mutex_unlock(&nready.mutex);

	}

	
}


void * create_consumer()
{

	for(int i = 0;i < 10;i++)
	{
		pthread_mutex_lock(&nready.mutex);
		while(nready.nready == 0)
				pthread_cond_wait(&nready.cond,&nready.mutex);
		nready.nready -- ;

		pthread_mutex_unlock(&nready.mutex);
		
		if(buff[i] != i)
		{
			printf("buff[%d] = %d was wrong!\n", i ,buff[i]);
			
		}
	}


	printf("All have scanned!\n");
	return (NULL);
}



int main(int argc, char const *argv[])
{
	pthread_t tid1,tid2;
	pthread_t consumer_tid;



	printf("I will create two producers and one consumers\n");

	if(pthread_create(&tid1,NULL,create_producer1,NULL) != 0)
		printf("create producer1 failed!\n");
	else
		printf("producer1 has been create!\n");



	if(pthread_create(&tid2,NULL,create_producer2,NULL) != 0)
		printf("create producer2 failed!\n");
	else
		printf("producer2 has been create!\n");


	if(pthread_create(&consumer_tid,NULL,create_consumer,NULL) != 0)
		printf("create consumer failed!\n");
	else
		printf("consumer has been create and begin check out the buff...\n");


//怎样等待线程结束呢。好像就直接这样接着写结束
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	pthread_join(consumer_tid,NULL);


	return 0;
}

运行截图为:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux下互斥锁实现的简单的生产者消费者问题 的相关文章

  • 是否从页面缓存中的脏页面进行文件读取?

    当字节写入文件时 内核不会立即将这些字节写入磁盘 而是将这些字节存储在页缓存中的脏页中 回写缓存 问题是 如果在脏页刷新到磁盘之前发出文件读取 则将从缓存中的脏页提供字节 还是首先将脏页刷新到磁盘 然后进行磁盘读取以提供字节 将它们存储在进
  • 如何从类似于 eclipse 的命令行创建可运行的 jar 文件

    我知道 eclipse 会生成一个可运行的 jar 文件 其中提取并包含在该 jar 文件中的所有库 jar 文件 从命令提示符手动创建 jar 文件时如何执行类似的操作 我需要将所有 lib jar 解压到类文件夹中吗 目前我正在使用 j
  • 如何在 Linux 主机上的 docker 容器中挂载目录 [重复]

    这个问题在这里已经有答案了 我想将一个目录从 docker 容器挂载到本地文件系统 该目录是网站根目录 我需要能够使用任何编辑器在本地计算机上编辑它 我知道我可以跑docker run v local path container path
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • Linux 上的 Python 3.6 tkinter 窗口图标错误

    我正在从 Python GUI 编程手册 学习 Python GUI 某项任务要求我通过将以下代码添加到我的配方中来更改窗口图标 Change the main windows icon win iconbitmap r C Python3
  • 如何从linux命令行运行.exe可执行文件? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 Windows 中有一个 abc exe 可执行文件 我可以使用 DOS 命令提示来执行此应用程序 并为其提供一些运行时变量 我想从
  • 如何查明 Ubuntu 上安装了哪个版本的 GTK+?

    我需要确定 Ubuntu 上安装了哪个版本的 GTK 男人似乎不帮忙 这个建议 https stackoverflow com a 126145 会告诉您安装了哪个 2 0 的次要版本 不同的主要版本将具有不同的包名称 因为它们可以在系统上
  • gentoo crontab:为什么这个简单的 crontab 不起作用?

    我使用 GENTOO 发行版 crontab e 35 12 root php5 home www cron php 当我手动运行时 php5 php5 home www cron php 这有效 它向我发送了一封电子邮件 然后我检查日期
  • 为什么在 Linux 上字符串文字的内存地址与其他字符串文字的内存地址如此不同?

    我注意到字符串文字在内存中的地址与其他常量和变量 Linux 操作系统 非常不同 它们有许多前导零 未打印 Example const char h Hi int i 1 printf p n void h printf p n void
  • Linux shell 脚本:十六进制数字到二进制字符串

    我正在 shell 脚本中寻找一些简单的方法来将十六进制数字转换为 0 和 1 字符的序列 Example 5F gt 01011111 是否有任何命令或简单的方法来完成它 或者我应该为其编写一些开关 echo ibase 16 obase
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • 从 TypeScript 运行任何 Linux 终端命令?

    有没有办法直接从 TypeScript 类中执行 Linux 终端命令 这个想法是做类似的事情 let myTerminal new LinuxTerminal let terminalResult myTerminal run sudo
  • 适用于 KDE 和 Gnome 的 Gui [重复]

    这个问题在这里已经有答案了 我想为一个现在是 CLI 的应用程序编写一个 gui 它需要在 KDE 和 Gnome DE 中 看起来不错 充分利用用户的外观设置 如果我选择 Qt 或 GTK 我能够做到这一点吗 它们与两个 DE 集成良好吗
  • 无需 cron 在后台发送邮件

    我想知道是否有一种方法可以运行 PHP 循环 以便在后台向订阅者发送几百封电子邮件 我的目标是格式化新闻通讯 单击发送 然后关闭浏览器或更改页面 当然 发送电子邮件的实际过程将在后台运行 不会因浏览器关闭而中断 我知道这可以通过 cron
  • Composer 安装要求

    我正在尝试将 Composer 安装到 Laravel 项目中 当我做的时候sudo composer install在项目目录中它显示了两个错误 Problem 1 Installation request for simplesoftw
  • 归档文件系统或格式

    我正在寻找一种文件类型来存储已退役系统的档案 目前 我们主要使用 tar gz 但从 200GB tar gz 存档中查找并提取几个文件是很麻烦的 因为 tar gz 不支持任何类型的随机访问读取规定 在你明白之前 使用 FUSE 安装 t
  • 没有可用的符号表信息

    我正在测试第三方的库 它崩溃了 当我想查看崩溃的原因时 我的 gdb 告诉我没有可用的调试符号 Program received signal SIGSEGV Segmentation fault Switching to Thread 0
  • SONAR - 使用 Cobertura 测量代码覆盖率

    我正在使用声纳来测量代码质量 我不知道的一件事是使用 Cobertura 测量代码覆盖率的步骤 我按照以下步骤操作http cobertura sourceforge net anttaskreference html http cober
  • 信号处理程序有单独的堆栈吗?

    信号处理程序是否有单独的堆栈 就像每个线程都有单独的堆栈一样 这是在 Linux C 环境中 来自 Linux 手册页signal 7 http kernel org doc man pages online pages man7 sign
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get

随机推荐

  • Spring配置的可选方案(三种配置方式)

    版权声明 xff1a 本文摘自 Spring实战 第4版 xff0c 美 Craig Walls 著 xff0c 张卫滨 译 本文仅作为学习与交流使用 xff0c 如有侵权请留言联系作者 转载请注明出处 目录 一 自动化装配Bean 注释
  • ftp工具

    本文会介绍java代码的ftp工具使用 xff0c 代码实现的功能难免不全 xff0c 要完整的体验ftp功能 xff0c 建议使用该ftp工具 xff1a iis7服务器管理工具 iis7服务器管理工具 xff08 曾用名 xff1a I
  • windows server 2000 r2 设置FTP文件服务器

    最近有一个需求需要将我们自己的一台windows服务器设置文件服务器 xff0c 小小记录一下 xff0c 设置过程 搭建IIS 第一步 xff1a 打开控制面板 第二步 xff1a 点击 打开或关闭 Windows 功能 第三步 xff1
  • ubuntu通过shell脚本实现服务自启和自动关机

    通常服务器开启后需要输入一大堆繁琐的进入文件 启动服务等命令 xff0c 每天如此就会逼着自己寻找捷径 xff0c 毕竟时间不用来学习就是在浪费生命嘛 xff1a Shell脚本挺身而出 xff1a 实现 xff1a 1 配置开机root账
  • 是什么导致了nginx.service: control process exited, code=exited status=1?

    是什么导致了nginx service control process exited code 61 exited status 61 1 xff1f 今天使用脚本安装nginx服务时遇到下面的问题 xff1a 那就先敲命令呗 xff0c
  • .jar与sources.jar区别

    首先 xff0c 当我们在下载jar包与引入jar包的时候可能会发现 xff0c 存在jar文件与相应的sources jar文件 如下图所示 xff1a 这个时候 xff0c 到底该下载哪一个 xff0c 或者我们需要的是哪一个 是jun
  • bat暂停5秒

    choice T 5 C ync CS D y n
  • Linux 开机自启动

    一 无界面的程序自启动 etc rc local 1 编辑 etc rc local vi etc rc local 2 添加要执行的命令 在exit 0 之前 注意 xff1a 这里的执行命令都必须是全路径的 xff0c 就算你添加到了
  • 使用firefox color自定义firefox的主题

    本说明基于firefox 79 轻量级主题 引用 xff1a firefox关于主题的说法 xff0c firefox现在仅支持轻量级主题了 那么什么是轻量级主题呢 xff1f mozilla官方并没有明确的定义 xff0c 我的理解是 x
  • TCL判断条件

    编写TCL代码时遇要写一个if判断条件 xff0c 很简单的一个语句 xff0c 结果却费了很大力气才搞定 要判断的是 xff0c 如果执行info exists成功而且某全局数组C的某个成员大于0 xff0c 正确的语句为 xff1a i
  • 实验二:线性时间选择

    实验二 xff1a 线性时间选择 问题描述 xff08 1 xff09 线性时间选择问题 给定线性序集中n个元素和一个整数k xff0c 1 lt 61 k lt 61 n 要求找出这n个元素中第k小的元素 xff0c 即如果将这个n个元素
  • 我的 IDEA 常用插件介绍

    本文同步发表于我的微信公众号 xff0c 在微信搜索 及格 即可关注 这篇文章介绍一下我 IDEA 里安装的插件 我的 IDEA 版本是IntelliJ IDEA 2021 3 3 xff0c 并且打上了官方的汉化包 xff0c 但我假设看
  • 在电脑上配置 protobuf + VS Code 开发环境

    工作需要学习 protobuf 开发 xff0c 如果能在 Windows 环境下使用更便于练习 xff0c 于是这篇文章介绍一下如何在 Windows 下借助 VS Code 配置 protobuf 开发环境 Protobuf 介绍 pr
  • 【CMake】gtest环境搭建与TDD入门(二)

    上一篇文章 xff0c 我们介绍了CMake xff1a 传送门 这一篇文章我暂时不打算继续写CMake相关的东西了 xff0c 转而写一个叫TDD的开发理论 xff0c 当然 xff0c 理论是需要实践支撑的 xff0c 利用CMake
  • 【刷机】给小米8输入PE12

    前言 我的小米8的官方开发版在两年前就停更了 最后一个版本是MIUI 12 20 9 4 有一个第三方网站收录小米ROM的 xff0c 最新只到MIUI 10 xff0c 很可惜我已经没有开发版权限了 xff0c 也下载不了完整包 xff0
  • 【elasticsearch + kibana】安装配置

    新年的第一篇文章 xff0c 由于工作需要 xff0c 在我自己的Windows电脑上配置elasticsearch 43 kibana xff0c 于是边做边记录 Elasticsearch 下载 xff1a Elasticsearch
  • 【WSL】Ubuntu 22.04 安装配置docker

    前言 WSL就是个坑 xff01 WSL就是个坑 xff01 WSL就是个坑 xff01 我第一次安装使用 Ubuntu 还是第一台笔记本 xff0c 装了双系统 xff0c 版本是18 04 LTS xff0c 但是我那个时候只有机械硬盘
  • 【Android】重新 build Android 项目遇到的问题

    没有理由重新build我的Android项目 xff0c 除了因为我C盘空间不足 但是发现C盘gradle的文件就占用了很大体积 xff08 4 7 G xff09 xff0c 因此决定把gradle换个位置 更换 gradle 位置 gr
  • 王道 —— 操作系统的四个特征

    1 知识总览 操作系统有并发 共享 虚拟 异步四个基本特征 xff0c 并发和共享是两个最基本的特征 xff0c 二者互为存在条件 xff1b 2 操作系统的特征 并发 并发 xff1a 指两个或者多个时间在同一时间间隔内发生 这些事件宏观
  • linux下互斥锁实现的简单的生产者消费者问题

    这个程序实现的功能很简单 xff0c 也算是入门linux下的多线程编程了吧 xff5e 其创造了两个生产者和一个消费者 xff0c 两个生产者通过互斥锁实现同步 xff0c 往缓冲区里放入数据 xff0c 数据的值和其下标值一样 xff0