多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区2种方法

生产者消费者问题:  该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。具体我就不解释了
  应该都懂 不懂请百度一下

我是用事件实现生产者消费者问题的同步  用临界区实现互斥    我的这个做法与经典做法不同 即用信号量的做法!   经典做法为法二

法一:

具体看代码:

#include <stdio.h>
#include <Windows.h>
#include <process.h>
int vol = 2;//缓冲区容量
int *g_pBuffer, g_BufferOff = 0, count;//依次为缓冲区,指向当前产品存放的位置, 目前缓冲区中产品数量
HANDLE g_ProducerEvent, g_ConsumerEvent;
CRITICAL_SECTION g_cs;//临界区
int ProNum = 10;//要生产的产品数量
int HasProduced = 0;//已经生产的个数
int HasConsumerd = 0;//已经消费的个数

unsigned int __stdcall FunPro(PVOID Pv)//生产者
{
	int k = *(int *)Pv;//生产者编号
	while(1)
	{
		WaitForSingleObject(g_ProducerEvent,  INFINITE);//等待生产者获取运行权限
		EnterCriticalSection(&g_cs);//申请临界区
		if(count < vol)//缓冲区未满
		{
			if(count == 0)//如果当前有0个产品
			{
				SetEvent(g_ProducerEvent);//让生产者运行
				ResetEvent(g_ConsumerEvent);//阻止消费者运行
			}
			else
			{
				SetEvent(g_ProducerEvent);//如果有多个产品 且缓冲区没满
				SetEvent(g_ConsumerEvent);	//让2者均可以运行
			}
			if(HasProduced >= ProNum)//生产的产品个数已经达到就不再生产了
			{
				LeaveCriticalSection(&g_cs);
				break;
			}
			count++;//生产了一个产品 当前产品数加1
			HasProduced++;//已经生产国多少个产品了 包括已经消费的
			g_BufferOff = (g_BufferOff + 1) % vol;//当前生产的产品要存储的位置
			g_pBuffer[g_BufferOff] = HasProduced;
			printf("生产者 %d 生产出一个产品,编号为 %d 存储位置%d 共有产品%d个 \n",k, HasProduced, g_BufferOff, count);
			Sleep(10);

		}
		else//缓冲区已满
		{
			ResetEvent(g_ProducerEvent);// 阻止生产者运行
			SetEvent(g_ConsumerEvent);//  让消费者运行
			Sleep(10);//
		}
		LeaveCriticalSection(&g_cs);//释放临界区

	}
	return 0;
}

unsigned int __stdcall FunCon(PVOID Pv)
{
	int k = *(int *)Pv;//消费者编号
    while(1)
	{
		WaitForSingleObject(g_ConsumerEvent,  INFINITE);//等待消费者获取运行权限
		EnterCriticalSection(&g_cs);//进入临界区
		if(count > 0)//如果当前有产品
		{
			if(count == vol)//如果缓冲区已满
			{
				ResetEvent(g_ProducerEvent);//让生产者不再运行
				SetEvent(g_ConsumerEvent);//让消费者赶紧运行消费
			}
			else//如果缓冲区不满  则设置2者均可运行
			{
				SetEvent(g_ProducerEvent);
				SetEvent(g_ConsumerEvent);
			}
			if(HasConsumerd>= ProNum)//如果已经消费的数量达到了要求的总产品数量 就不再消费 别忘记释放临界区!
			{
				LeaveCriticalSection(&g_cs);
				break;
			}
			printf("消费者%d消费了一个产品  编号为%d 它存放在坐标%d 还剩产品%d个\n", k, g_pBuffer[g_BufferOff], g_BufferOff, count - 1);
			count--;
			HasConsumerd++;
			g_BufferOff = (g_BufferOff - 1 + 10) % vol;
			Sleep(100);
		}
		else//当前无产品
		{
			ResetEvent(g_ConsumerEvent);
			SetEvent(g_ProducerEvent);
			Sleep(100);
		}
		LeaveCriticalSection(&g_cs);
	}
	return 0;
}
int main()
{
	HANDLE Producer1, Producer2, Producer3, Consumer, Consumer2;
    g_BufferOff = -1;
	count = 0;
	g_pBuffer = new int [vol];
	int k1 = 1, k2 = 2, k3 = 3, t1 = 1, t2 = 2;

	//初始化临界区 创建事件  创建线程
	InitializeCriticalSection(&g_cs);
	g_ProducerEvent = CreateEvent(NULL, TRUE, TRUE, "Producer");
	g_ConsumerEvent = CreateEvent(NULL, TRUE, FALSE, "Consumer");
	Producer1 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k1, 0, NULL);
	Producer2 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k2, 0, NULL);
	Producer3 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k3, 0, NULL);
	Consumer = (HANDLE)_beginthreadex(NULL, 0, FunCon, &t1, 0, NULL);
	Consumer2 = (HANDLE)_beginthreadex(NULL, 0, FunCon, &t2, 0, NULL);
	Sleep(15000000);

	//以下全是销毁工作
	CloseHandle(g_ConsumerEvent);
	CloseHandle(g_ProducerEvent);
	CloseHandle(Producer1);
	CloseHandle(Producer2);
	CloseHandle(Producer3);
	CloseHandle(Consumer);
	CloseHandle(Consumer2);
    delete []g_pBuffer;
	DeleteCriticalSection(&g_cs);
	system("pause");
	return 0;
}

法二:

#include <stdio.h>
#include <Windows.h>
#include <process.h>
int g_vol = 10;//缓冲区容量
int *g_pBuffer, g_BufferOff = -1, count;//依次为缓冲区,指向当前产品存放的位置, 目前缓冲区中产品数量
HANDLE g_hSemaphoreFull, g_hSemaphoreEmpty;//缓冲区已用位置信号量 未用位置信号量句柄
CRITICAL_SECTION g_cs;//临界区
int g_ProNum = 20;//要生产的产品数量
int g_HasProduced = 0;//已经生产了的产品数量
int g_HasConsumerd = 0;
unsigned int __stdcall FunPro(PVOID Pv)//生产者
{
	int k = *(int *)Pv;//生产者编号
    while(1)
	{
            WaitForSingleObject(g_hSemaphoreEmpty, INFINITE);
			EnterCriticalSection(&g_cs);
			if(g_HasProduced >= g_ProNum) break;
            g_HasProduced++;//已经生产国多少个产品了 包括已经消费的
            g_BufferOff = (g_BufferOff + 1) % g_vol;//当前生产的产品要存储的位置
            g_pBuffer[g_BufferOff] = g_HasProduced;
            printf("生产者 %d 生产出一个产品,编号为 %d 存储位置%d \n",k, g_HasProduced, g_BufferOff);
            ReleaseSemaphore(g_hSemaphoreFull, 1, NULL);//将Full信号量+1   表示已经有了一个产品
			LeaveCriticalSection(&g_cs);
			Sleep(10); 

	}
	return 0;
}

unsigned int __stdcall FunCon(PVOID Pv)
{
	int k = *(int *)Pv;//消费者编号
    while(1)
	{
			WaitForSingleObject(g_hSemaphoreFull, INFINITE);
			EnterCriticalSection(&g_cs);
			if(g_HasConsumerd >= g_ProNum) break;
			printf("消费者%d消费了一个产品  编号为%d 它存放在坐标%d \n", k, g_pBuffer[g_BufferOff], g_BufferOff);
            count--;
            g_HasConsumerd++;
            g_BufferOff = (g_BufferOff - 1 + 10) % g_vol;
			ReleaseSemaphore(g_hSemaphoreEmpty, 1, NULL);
		    LeaveCriticalSection(&g_cs);
            Sleep(100);
	}
	return 0;
}
int main()
{
	HANDLE Producer1, Producer2, Producer3, Consumer, Consumer2;
    g_BufferOff = -1;
	count = 0;
	g_pBuffer = new int [g_vol];
	int k1 = 1, k2 = 2, k3 = 3, t1 = 1, t2 = 2;

	//初始化临界区 创建事件  创建线程
	InitializeCriticalSection(&g_cs);
    g_hSemaphoreFull = CreateSemaphore(NULL, 0 , 100, "Full");//创建信号量 初始资源数量为0  最大并发数量我设置的100
	g_hSemaphoreEmpty = CreateSemaphore(NULL, g_vol, 100, "Empty");
	Producer1 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k1, 0, NULL);
	Producer2 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k2, 0, NULL);
	Producer3 = (HANDLE)_beginthreadex(NULL, 0, FunPro, &k3, 0, NULL);
	Consumer = (HANDLE)_beginthreadex(NULL, 0, FunCon, &t1, 0, NULL);
	Consumer2 = (HANDLE)_beginthreadex(NULL, 0, FunCon, &t2, 0, NULL);
	Sleep(15000000);

	//以下全是销毁工作
	CloseHandle(g_hSemaphoreFull);
	CloseHandle(g_hSemaphoreEmpty);
	CloseHandle(Producer1);
	CloseHandle(Producer2);
	CloseHandle(Producer3);
	CloseHandle(Consumer);
	CloseHandle(Consumer2);
    delete []g_pBuffer;
	DeleteCriticalSection(&g_cs);
	system("pause");
	return 0;
}

多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区2种方法

时间: 2024-10-09 22:56:54

多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区2种方法的相关文章

基于Java 生产者消费者模式(详细分析)

本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模式(单面包)6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模

多线程应用——生产者消费者问题

前言 生产者和消费者问题是多线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞. 在JAVA中实现生产者消费者问题时,有三种常用的方式: 使用Object的wait/notify的消息通知机制 使用Lock的Condition的await/signal的消息通知机制 使用BlockingQueue实现.本文主要将这三种实现方式进行总结归纳 下面本文将分别采用以上三种

利用多线程编写 生产者-消费者 关系

package ace; import java.util.ArrayList; import java.util.Timer; import java.util.TimerTask; /** * 利用多线程编写 生产者-消费者 关系 */ public class ProductionAndConsumption { private static ArrayList<String> products = new ArrayList<String>(); // 产品 private

JAVA多线程之生产者消费者

生产者消费者并发编程: 假设仓库有10个仓位,分别有10个生产者和10个消费者,生产者不断生产产品,放入仓库的仓位中,而消费者则不断从仓库中获取产品, 如果仓库已满,则生产者要等待,等消费者消费后,空出仓位后,再继续放入产品. 反之如果仓库已空,则消费者要等待,等待生产者生产出产品后,再继续消费产品. 关于生产者.消费者有四种实现方式 1,wait,nofity方式 2,ReentrantLock锁的await()和signal() 3,阻塞队列的方式 4,Semaphore 信号量方式 下面分

java多线程解决生产者消费者问题

import java.util.ArrayList; import java.util.List; /** * Created by ccc on 16-4-27. */ public class Test { public static void main(String[] args) { GunClip clip = new GunClip(); Producer p = new Producer(clip); customer c = new customer(clip); p.star

java多线程模拟生产者消费者问题,公司面试常常问的题。。。

package com.cn.test3; //java多线程模拟生产者消费者问题 //ProducerConsumer是主类,Producer生产者,Consumer消费者,Product产品 //Storage仓库 //批注:我把输出结果写在程序以下了,你能够看一下,事实上非常easy的,你想象一下产品从生产,到取出的一个生产线,我们定义两个线程,生产者线程,和消费者线程,一个是生产者不停的生产产品并放入数量有限的指定槽内,而消费者从指定槽依次取出产品,现实中的流水车间也相似于此. publ

Android-Java多线程通讯(生产者 消费者)&amp;10条线程对-等待唤醒/机制的管理

上一篇博客 Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 是两条线程(Thread-0 / Thread-1) 在被CPU随机切换执行: 而今天这篇博客是,在上一篇博客Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 的基础上,扩大规模增加10条线程去执行 生产者 消费者: 注意:?? 上一篇博客是两条线程在执行(生产者 消费者)例如:当Thread-0 锁.wait(); 等待 冻结后,  Thread-1 锁.notify(); 唤醒的一定是 T

事件监听的三种方法

事件监听的三种方法: addTarget --用于监听一些点击.值改变等事件 代理       -- 监听一些开始.结束.选中某行等一些改变控制属性的一些事件 通知:上面都不行考虑使用通知 通知使用注意:只要监听通知就要移除通知,否则控制器销毁后,通知发送时就会找不到对象导致程序崩溃 文本框事件的监听: textfied代理只能监听开始编辑结束编辑,能否改变文字,不能监听改变文字后的情况,本项目需要 监听文本框中是否有输入,代理和addTarget都不适用. 文本框发出的三个通知: UIKIT_

java多线程--“升级版”生产者消费者

ReentrantLock介绍 ReentrantLock是一个可重入的互斥锁,又被称为"独占锁". 顾名思义,ReentrantLock锁在同一个时间点只能被一个线程锁持有:而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取. ReentrantLock分为"公平锁"和"非公平锁".它们的区别体现在获取锁的机制上是否公平."锁"是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock