怎样用C++实现生产者消费者的模拟

2025-04-18 22:54:11
推荐回答(2个)
回答1:

// producer_consumer.cpp
//////////////////////////////////////////////////////////////////////
// 有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,
// 在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓
// 冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消
// 费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
//////////////////////////////////////////////////////////////////////

#include 
#include 
#include 
#include 


const int BUFFER_LENGTH = 100;
int buffer[BUFFER_LENGTH];
int front = 0, rear = -1; // 缓冲区的前端和尾端
int size = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *producer(void *arg);
void *consumer(void *arg);

int main(int argc, char **argv)
{
    pthread_t producer_id;
    pthread_t consumer_id;

    pthread_create(&producer_id, NULL, producer, NULL);
    
    pthread_create(&consumer_id, NULL, consumer, NULL);
    
//主线程运行结束,子线程也就运行结束了
//http://bbs.chinaunix.net/thread-1286290-1-1.html
    sleep(1);

    return 0;
}

void *producer(void *arg)
{    
   //pthread_detach(threadid)函数的功能是使线程ID为threadid的线程处于分离状态,一旦线程处于分离状态,
  //该线程终止时底 层资源立即被回收;否则终止子线程的状态会一直保存(占用系统资源)直到主线程调用pthread_join(threadid,NULL)获取线程的退 出状态。
  //通常是主线程使用pthread_create()创建子线程以后,一般可以调用pthread_detach(threadid)分离刚刚创建的子线程,
 
  //这里的threadid是指子线程的threadid;如此以来,该子线程止时底层资源立即被回收;
  //被创建的子线程也可以自己分离自己,子线程调用pthread_detach(pthread_self())就是分离自己,
 //因为pthread_self()这个函数返回的就是自己本身的线程ID;
    pthread_detach(pthread_self());
    
    while (true)
    {
        pthread_mutex_lock(&mutex);
        while (size == BUFFER_LENGTH) // 如果缓冲区已满,等待; 否则,添加新产品
        {
            printf("buffer is full. producer is waiting...\n");
            pthread_cond_wait(&cond, &mutex);
        }
        // 往尾端添加一个产品
        rear = (rear + 1) % BUFFER_LENGTH;
        buffer[rear] = rand() % BUFFER_LENGTH;
        printf("producer produces the item %d: %d\n", rear, buffer[rear]);
        ++size;
        if (size == 1) // 如果当前size=1, 说明以前size=0, 消费者在等待,则给消费者发信号
        {
           pthread_cond_signal(&cond);
        }
        pthread_mutex_unlock(&mutex);
    }
}

void *consumer(void *arg)
{
    pthread_detach(pthread_self());
    
    while (true)
    {
        pthread_mutex_lock(&mutex);
        while(size == 0) // 如果缓冲区已空,等待; 否则,消费产品
        {
            printf("buffer is empty. consumer is waiting...\n");
            pthread_cond_wait(&cond, &mutex);
        }
        // 从前端消费一个产品
        printf("consumer consumes an item%d: %d\n", front, buffer[front]);
        front = (front + 1) % BUFFER_LENGTH;
        --size;
        if (size == BUFFER_LENGTH-1) // 如果当前size=BUFFER_LENGTH-1,说明以前生产者在等待,则给生产者发信号
        {
            pthread_cond_signal(&cond);
        }
        pthread_mutex_unlock(&mutex);
    }
}

回答2:

感觉你问的应该是 操作系统 课程当中的生产者消费者模式的模拟,是线程同步的简单模拟,因为问的问题描述不是很清楚,我就当是这个了。

因为C++是不支持多线程的,需要借助操作系统的API,我就以Windows下为例

#include 

DWORD sum;    //简单说DWORD是int
HANDLE g_hProduct;   //生产者等待的事件
HANDLE g_hConsume;   //消费者等待的事件

//生产者线程
DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
DWORD id;
for(int i=0 ; i < 10 ; i++)
{
        //第一次循环不会堵塞,因为创建出来就是有信号的
WaitForSingleObject(g_hProduct, INFINITE);
sum = 1;
id = GetCurrentThreadId();
printf("生产者%d将1放入sum\n", id);

Sleep(1000);
SetEvent(g_hConsume);
}

return 0;
}

//消费者线程
DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
DWORD id;
for(int i=0 ; i < 10 ; i++)
{
        //第一次循环会堵塞,因为创建出来就是没有信号的
WaitForSingleObject(g_hConsume, INFINITE);
sum = 0;
id = GetCurrentThreadId();
printf("----消费者%d将0放入sum\n", id);

Sleep(1000);
SetEvent(g_hProduct);
}

return 0;
}

int main(int argc, char* argv[])
{
HANDLE handle[2];

g_hProduct = CreateEvent(NULL, FALSE, TRUE, NULL);
g_hConsume = CreateEvent(NULL, FALSE, FALSE, NULL);
        
        //handle[0]是生产者线程句柄     handle[1]是消费者的
handle[0] = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
handle[1] = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);

//等待两个线程结束
WaitForMultipleObjects(2, handle, TRUE, INFINITE);

CloseHandle(handle[0]);
CloseHandle(handle[1]);

printf("\n\nHello World!\n");
return 0;
}

原理是用的【事件】的信号状态,生产者线程创建出来就是有信号的,消费者线程创建出来就是等待,当生产者完成一次循环后,将消费者等待的信号激活,此时消费者线程就会往下执行,消费者线程循环的最后一个步骤是将生产者的信号激活,交替执行。

两个线程都是等待信号,每次循环的开始都等待自己的信号,每次循环结束时都是将对方的信号激活,但是,生产者线程是从创建出来就有信号的,所以第一次循环不会堵塞。

如果对这几个函数不清楚的话,你可以查一下MSDN,如果没有的话我发。