多线程实现生产消费者模型(含代码)

实验题目:多线程实现生产消费者模型(程序可在Linux下和VS2019中运行)
实验要求:1.生产者4个,消费者8个,仓库容量20个,初始为10个。
---------------2.生产者和消费者生产消费完毕后需要休眠一段时间。
---------------3.货物为随机产生的大写字母。
实验环境:1.windows11、visual studio 2019 X86
---------------2.Linux、ubuntu20、gcc7.4.0、secureCRT4.0、notepad++
参考内容: 无法打开pthread.h
注意:1. pthread的下载链接为:
https://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip
-------- 2.请注意 参考内容 “无法打开pthread.h” 内的2.3 dll文件内x86 下的文件复制到C:\Windows\SysWOW64

一、使用条件变量和互斥锁

1.原理

在这里插入图片描述
从上图中可以看出在不满足条件下,消费者线程会进入触发pthread_cond_wait(&g_cond,&g_mutex),然后该消费者线程被进入条件队列,并释放锁(该锁由条件变量释放);这时生产者抢到锁,生产,释放信号量,解锁;当条件队列当中的等待的消费者线程接收到该信号后,上锁(紧接着pthread_cond_wait()后进行,上锁由条件变量进行),消费,解锁。这样就完成了一个条件变量和互斥锁的相互使用。

2.程序

/*!
*************************************************************************************************
* @file  main.cpp
* @brief producer consumer model Production consumption model
* @author Super Pallet-Town Man
* date 2022/9/10
*************************************************************************************************
*/
// Windows system
#include <windows.h>

//Linux use
//#include <unistd.h>

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

#define CONSUMERS_NEMBER 4
#define PRODUCERS_NEMBER 2
#define MAX_BUDDER_SIZE 20
#define INIT_BUFFER_SIZE 10

pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;
pthread_t g_threadConsumers[CONSUMERS_NEMBER];
pthread_t g_threadProducers[PRODUCERS_NEMBER];

typedef struct _ST_BUF
{
    int iCount;
    char strArray[MAX_BUDDER_SIZE + 1];
}ST_BUF;
static ST_BUF stBuf = { INIT_BUFFER_SIZE , {0}};

/*!
 * @brief generate random letters
 *
 * @return letter
 */
char getRandLetter()
{
    char letter;
    letter = (char)((rand() % 26) + 'A');
    return letter;
}

/*!
 * @brief consumer model function
 * 
 * @param[in] arg the serial number
 * 
 * @return NULL to end
 */
void* consumer(void* arg)
{
    if (NULL == arg)
    {
        exit(-1);
    }
    int num = *(int*)arg;
    while (1)
    {
        pthread_mutex_lock(&g_mutex);

        while (stBuf.iCount == 0)
        {
            pthread_cond_wait(&g_cond, &g_mutex);
        }
        stBuf.iCount--;
        printf("[Consumer %d] consumer [%c]  ", num, stBuf.strArray[stBuf.iCount]);
        stBuf.strArray[stBuf.iCount] = 0;
        printf("%s\n", stBuf.strArray);
        pthread_cond_signal(&g_cond);
        pthread_mutex_unlock(&g_mutex);

        Sleep((rand() % 200) * 10);//in windows system, Sleep() is ms
        //usleep((rand() % 200) * 1000);//Linux use
    }
    return NULL;
}

/*!
 * @brief producer model function
 *
 * @param[in] arg the serial number
 *
 * @return NULL to end
 */
void* producer(void* arg)
{
    if (NULL == arg)
    {
        exit(-1);
    }
    int num = *(int*)arg;
    char ch = 0;
    while (1)
    {
        pthread_mutex_lock(&g_mutex);

        while (stBuf.iCount >= MAX_BUDDER_SIZE)
        {
            pthread_cond_wait(&g_cond, &g_mutex);
        }
        ch = getRandLetter();
        printf("[Producer %d] produce  [%c]  ", num, ch);
        stBuf.strArray[stBuf.iCount++] = ch;
        printf("%s\n", stBuf.strArray);
        pthread_cond_signal(&g_cond);
        pthread_mutex_unlock(&g_mutex);

        Sleep((rand() % 100) * 10);//in windows system, Sleep() is ms
        //usleep((rand() % 100) * 1000);//Linux use
    }
    return NULL;
}

/*!
 * @brief main function
 */
int main()
{
    pthread_mutex_init(&g_mutex, NULL);
    pthread_cond_init(&g_cond, NULL);
    char strArrayInit[INIT_BUFFER_SIZE + 1] = { 0 };
    for (int i = 0; i < INIT_BUFFER_SIZE; i++)
    {
        strArrayInit[i] = getRandLetter();
    }
    memcpy(stBuf.strArray, strArrayInit, INIT_BUFFER_SIZE);

    for (int i = 0; i < PRODUCERS_NEMBER; i++)
    {
        pthread_create(&g_threadProducers[i], NULL, producer, (void*)&i);
        Sleep(1);
        //usleep(1000);//Linux use
    }
    for (int j = 0; j < CONSUMERS_NEMBER; j++)
    {
        pthread_create(&g_threadConsumers[j], NULL, consumer, (void*)&j);
        Sleep(1);
        //usleep(1000);//Linux use
    }
    for (int i = 0; i < CONSUMERS_NEMBER; i++)
    {
        pthread_join(g_threadConsumers[i], NULL);
    }
    for (int j = 0; j < PRODUCERS_NEMBER; j++)
    {
        pthread_join(g_threadProducers[j], NULL);
    }

    pthread_mutex_destroy(&g_mutex);
    pthread_cond_destroy(&g_cond);
    return 0;
}

二、只使用互斥锁的程序

这里只将列出了修改的代码(consumer 和 producer 的API),其余部分一致

/*!
 * @brief consumer model function
 * 
 * @param[in] arg the serial number
 * 
 * @return NULL to end
 */
void* consumer(void* arg)
{
    if (NULL == arg)
    {
        exit(-1);
    }
    int num = *(int*)arg;
    while (1)
    {
        pthread_mutex_lock(&g_mutex);

        if (stBuf.iCount > 0)
        {
            stBuf.iCount--;
            printf("[Consumer %d] consumer [%c]  ", num, stBuf.strArray[stBuf.iCount]);
            stBuf.strArray[stBuf.iCount] = 0;
            printf("%s\n", stBuf.strArray);
        }

        pthread_mutex_unlock(&g_mutex);
        Sleep((rand() % 200) * 10);//in windows system, Sleep() is ms
        //usleep((rand() % 200) * 1000);//Linux use
    }
    return NULL;
}

/*!
 * @brief producer model function
 *
 * @param[in] arg the serial number
 *
 * @return NULL to end
 */
void* producer(void* arg)
{
    printf("%d   ", pthread_self());
    if (NULL == arg)
    {
        exit(-1);
    }
    int num = *(int*)arg;
    char ch = 0;
    while (1)
    {
        pthread_mutex_lock(&g_mutex);

        if (stBuf.iCount < MAX_BUDDER_SIZE)
        {
            ch = getRandLetter();
            printf("[Producer %d] produce  [%c]  ", num, ch);
            stBuf.strArray[stBuf.iCount++] = ch;
            printf("%s\n", stBuf.strArray);
        }

        pthread_mutex_unlock(&g_mutex);
        Sleep((rand() % 100) * 10);//in windows system, Sleep() is ms
        //usleep((rand() % 100) * 1000);//Linux use
    }
    return NULL;
}

三、实验结果

存在问题:VS2019下的两个生产者不论相隔多远,都会产生同样的随机字母,问题无法找出,怀疑是pthread.h相关兼容性问题产生。或者是rand()函数的问题?或者是Sleep函数的问题?

1.VS2019下生成的结果
请添加图片描述
2.linux下生成结果
请添加图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值