多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区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; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。