生产者与消费者问题

设计要求

1.创建生产者和消费者线程

创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。

2.生产和消费的规则

在按照上述要求创建线程进行相应的读写操作时,还需要符合以下要求:

①共享缓冲区存在空闲空间时,生产者即可使用共享缓冲区。

②某一生产者生产一个产品后,可能不止一个消费者,或者一个消费者多次地请求消费该产品。此时,只有当所有的消费需求都被满足以后,该产品所在的共享缓冲区才可以被释放,并作为空闲空间允许新的生产者使用。  

③每个消费者线程的各个消费需求之间存在先后顺序。例如信息“5 C 3 l 2 4”,可知这代表一个消费者线程,该线程请求消费1,2,4号生产者线程生产的产品。而这种消费是有严格顺序的,消费1号线程产品的请求得到满足后才能继续往下请求2号生产者线程的产品。  

④要求在每个线程发出读写操作申请、开始读写操作和结束读写操作时分别显示提示信息。

设计思想

1.开辟一块缓冲区,由生产者和消费者共享。生产者可生产资源,消费者可消费资源。

2.创建互斥信号量,实现生产者消费者的互斥,即正在生产无法消费,正在消费无法生产。

3.创建生产者进程和消费者进程,并实现进程同步。

代码实现

#include <windows.h>
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
const int SIZE_OF_BUFFER = 10;   //缓冲区长度
int  ConsumeID ;

int g_buffer[SIZE_OF_BUFFER];               //缓冲区队列
bool g_continue = true;                     //控制程序结束
HANDLE g_hMutex;                            //用于线程间的互斥
//LPVOID 相当于void*,任意类型的指针,如果这个指针指向的内存在加上任何强制转换后,都会尝试按照这种类型进行转换
//Windows系统的应用程序接口,是C/C++调用约定的一种,意思是函数的参数被从右到左推送到堆栈上,被调用函数在返回之前从堆栈中弹出这些参数。
DWORD  WINAPI Producer(LPVOID);              //生产者线程,dword 变量类型的内存占位
DWORD  WINAPI Consumer(LPVOID);              //消费者线程
int flag;
int thefirst;
int main()
{

    //创建各个互斥信号
    g_hMutex = CreateMutex(NULL, FALSE, NULL); //一参:默认安全性,二参:初始化互斥对象所有者,三参指向互斥对象名的指针
    CreateSemaphore(NULL, 0, SIZE_OF_BUFFER, NULL);//创建信号灯,createsemaphore常常被用作多线程同步
    CreateSemaphore(NULL, SIZE_OF_BUFFER,
                                    SIZE_OF_BUFFER, NULL);
    //缓冲区初始化
    for (int i = 0; i< SIZE_OF_BUFFER; ++i)
    {
        g_buffer[i] = -1;   //当值为-1时该项为空
    }
    flag=1;
    thefirst=1;
    const int PRODUCERS_COUNT = 1;       //生产者的个数
    const int CONSUMERS_COUNT = 1;       //消费者的个数
    //总的线程数
    const int THREADS_COUNT = PRODUCERS_COUNT + CONSUMERS_COUNT;
    HANDLE hThreads[THREADS_COUNT];     //各线程的handle
    DWORD producerID[PRODUCERS_COUNT];  //生产者线程的标识符  DWORN 32位无符号整数相当于unsigned long int
    DWORD consumerID[CONSUMERS_COUNT];  //消费者线程的标识符
    //创建生产者线程
    hThreads[0]= CreateThread(NULL, 0, Producer, NULL, 0, &producerID[0]);//CreateThread是window提供的API函数
    hThreads[1]= CreateThread(NULL, 0, Consumer, NULL, 0, &consumerID[0]);//第一个参数,使用默认的安全性;第二个参数,使用与调用函数的线程相同的栈大小
                                   //第三个参数,线程函数入口;第四个参数,传递给线程的参数,第五个参数,线程创建后
                                   //立即运行,第六个参数,新线程的ID
    while (g_continue){}
}
//把新生产的产品放入缓冲区
void Append()
{
    //cout << "正在生产产品 ... ";
    if(!flag||thefirst)
        for(int i=0; i<SIZE_OF_BUFFER; i++)
        {
            if(g_buffer[i]==-1)
            {
                cout << endl << "正在生产产品 " << i << " ... ";
                cout << "成功" << endl;
                g_buffer[i] = 1;
                Sleep(500);
            }
            thefirst=0;
        }
}

//从缓冲区中取出一个产品
void Take()
{
    cout<<endl;
    cout<<"请输入消费者名称、需要消费产品的数量和产品标号"<<endl;
    string name;
    int n;
    cin>>name>>n;
    int con[n];
    for(int i=0; i<n; i++)
        cin>>con[i];
    for(int i=0; i<n; i++)
    {
        ConsumeID=con[i];
        Sleep(500);
        cout << name << "正在取产品 ... ";
        if(g_buffer[ConsumeID]==1)
        {
            g_buffer[ConsumeID] = -1;
            cout << ConsumeID << "--成功" << endl;
            cout << "消费 " << ConsumeID << " ... ";
            cout << "成功" << endl;
        }
        else
        {
            cout << ConsumeID << "--失败" << endl;
            flag=0;
            Append();
            i--;
        }
        flag=1;
    }
}

//生产者
DWORD  WINAPI Producer(LPVOID)
{
    while (g_continue)
    {
        Sleep(1000);
        //等待信号灯
        WaitForSingleObject(g_hMutex, INFINITE);
        Append();
        ReleaseMutex(g_hMutex);
    }
    return 0;
}

//消费者
DWORD  WINAPI Consumer(LPVOID)
{
    while (g_continue)
    {
        Sleep(2000);//该线程释放当前的控制权2000毫秒,让系统调度其他线程
        WaitForSingleObject(g_hMutex, INFINITE);
        Take();
        ReleaseMutex(g_hMutex);
    }
    return 0;
}

 

运行实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值