基于Windows的进程互斥实现机制(生产者消费者模拟)

作者:非妃是公主
专栏:《操作系统》
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
在这里插入图片描述

专栏地址

《操作系统》专栏地址

专栏系列文章

操作系统复习01:引言

操作系统复习02:进程

操作系统复习03:输入输出系统

操作系统复习04:存储管理

操作系统复习05:文件系统

基于Windows的进程互斥实现机制(生产者消费者模拟)

Ubuntu操作系统+虚拟机virtualBox配置共享文件夹(实现主机和虚拟机之间文件资源共享)

需求规格说明

基于QT Creator环境的多线程编程验证互斥的原理,通过使用semaphore,mutex等控制变量,实现对生产者消费者模型的真实模拟。调用了Qt多线程类库QThread进行实现,文件结构如下:其中PandC中主要写了生产者消费者相关函数,OSWork_1主要是前端界面显示的Qt类。
在这里插入图片描述

设计表示

生产者类的设计如下:

class Producer : public QThread
{
   Q_OBJECT
protected:
   void run();
signals:
   void pro(int c);
public:
   //线程退出的标识量
   volatile bool m_stop;
   Producer()
   {
       m_stop = false;      
   }
   //线程退出的接口函数,用户使用
   void stop()
   {
       m_stop = true;
       
   }
};

消费者的类设计如下:

class Consumer : public QThread
{
    Q_OBJECT
protected:
    void run();
signals:
    void con(int c);
public:
    //线程退出的标识量
    volatile bool m_stop;
    Consumer()
    {
        m_stop = false;
    }
    //线程退出的接口函数,用户使用
    void stop()
    {
        m_stop = true;
        
    }
};

详细设计表示

生产者访问缓冲区:主要通过线程锁unique_lock进行实现,它可以将信号量mutex锁住,在作用域范围内,只能一个线程访问临界区。其中,hcnum为缓冲区数量,sleep为休眠一定时间,通过它来控制生产者生产的速度。

void Producer::run() {
	int data1;
	while (!m_stop) {//通过外层循环,能保证生成用不停止
		if (c < hcnum) {//限流
			{
				data1 = rand();
				unique_lock<mutex> locker(mu);//锁
				q.push_front(data1);
				qDebug() << "存了" << data1 << endl;
				if (c == 1)
					cond.notify_one(); // 通知取
				++c;	
				
			}
			emit pro(c);
			Sleep(PSTime);
		}
	}
}

消费者访问缓冲区:功能和生产者正好互补,通过unique_lock,锁住信号量,确保生产者进程和消费者进程中,只能有一个留在缓冲区中。如果队列为空,那么说明消费者进程应该被阻塞进入阻塞队列,同时释放信号量,以便让生产者进程可以进入临界区生产。

void Producer::run() {
	int data1;
	while (!m_stop) {//通过外层循环,能保证生成用不停止
		if (c < hcnum) {//限流
			{
				data1 = rand();
				unique_lock<mutex> locker(mu);//锁
				q.push_front(data1);
				qDebug() << "存了" << data1 << endl;
				if (c == 1)
					cond.notify_one(); // 通知取
				++c;
			}
			emit pro(c);
			Sleep(PSTime);
		}
	}
}

“前后端”源文件间缓冲区数量通信:主要通过extern的方式,共享生产者生产速度和消费者消费速度这两个变量。

extern int PSTime = 1100;
extern int CSTime = 1100;

缓冲区数量显示:在创建生产者、消费者进程的时候,通过connect将concumer中的信号与前端OSWork_1中的显示函数关联到一起,进而实现生产者消费者进程对前端界面动态更新。

void OSWork_1::ReStart() {
  if (!producer) {
      producer = new Producer;
      connect(producer, &Producer::pro, this, &OSWork_1::display);
      producer->start();
  }
  if (!consumer) {
      consumer = new Consumer;
      connect(consumer, &Consumer::con, this, &OSWork_1::display);
      consumer->start();
  }
}

缓冲区数量显示主要通过10个label,根据不同颜色进行不同的显示。核心代码如下:
在这里插入图片描述

软件运行后,主界面如下: 在这里插入图片描述

源代码

//OSWork_1.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QMainWindow>
#include <qpalette.h>
#include "ui_OSWork_1.h"
#include"PandC.h"
#include <qpushbutton.h>
#include <qdebug.h>

class OSWork_1 : public QMainWindow
{
    Q_OBJECT
public:
    QPalette pe1;
    QPalette pe2;
    Producer* producer;
    Consumer* consumer;
    OSWork_1();
    void display(int c);
    void ReStart();
    void End();
    void add_p();
    void sub_p();
    void add_c();
    void sub_c();
    ~OSWork_1();
private:
    Ui::OSWork_1Class ui;
};
//PandC.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QThread>
#include <QDebug>
#include<qpalette.h>
#include <deque>
#include <mutex>
#include <condition_variable>
#include<Windows.h>
#include <qlabel.h>

class Producer : public QThread
{
    Q_OBJECT
protected:

    void run();
signals:
    void pro(int c);
public:
    //线程退出的标识量
    volatile bool m_stop;
    Producer()
    {
        m_stop = false;
    }
    //线程退出的接口函数,用户使用
    void stop()
    {
        m_stop = true;
    }

};

class Consumer : public QThread
{
    Q_OBJECT
protected:
    void run();
signals:
    void con(int c);
public:
    //线程退出的标识量
    volatile bool m_stop;
    Consumer()
    {
        m_stop = false;
    }
    //线程退出的接口函数,用户使用
    void stop()
    {
        m_stop = true;
    }
};
//OSWork_1.cpp
#include "OSWork_1.h"
extern int PSTime;
extern int CSTime;

void OSWork_1::display(int c) {
    ui.label_1->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_2->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_3->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_4->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_5->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_6->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_7->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_8->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_9->setAutoFillBackground(true);  //一定要这句,否则不行
    ui.label_10->setAutoFillBackground(true);  //一定要这句,否则不行

    switch (c)
    {
    case 0:
        ui.label_1->setPalette(pe2);        
        ui.label_2->setPalette(pe2);
        ui.label_3->setPalette(pe2);
        ui.label_4->setPalette(pe2);
        ui.label_5->setPalette(pe2);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 1:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe2);
        ui.label_3->setPalette(pe2);
        ui.label_4->setPalette(pe2);
        ui.label_5->setPalette(pe2);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 2:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe2);
        ui.label_4->setPalette(pe2);
        ui.label_5->setPalette(pe2);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 3:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe2);
        ui.label_5->setPalette(pe2);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 4:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe2);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 5:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe2);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 6:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe1);
        ui.label_7->setPalette(pe2);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 7:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe1);
        ui.label_7->setPalette(pe1);
        ui.label_8->setPalette(pe2);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 8:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe1);
        ui.label_7->setPalette(pe1);
        ui.label_8->setPalette(pe1);
        ui.label_9->setPalette(pe2);
        ui.label_10->setPalette(pe2);
        break;
    case 9:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe1);
        ui.label_7->setPalette(pe1);
        ui.label_8->setPalette(pe1);
        ui.label_9->setPalette(pe1);
        ui.label_10->setPalette(pe2);
        break;
    case 10:
        ui.label_1->setPalette(pe1);
        ui.label_2->setPalette(pe1);
        ui.label_3->setPalette(pe1);
        ui.label_4->setPalette(pe1);
        ui.label_5->setPalette(pe1);
        ui.label_6->setPalette(pe1);
        ui.label_7->setPalette(pe1);
        ui.label_8->setPalette(pe1);
        ui.label_9->setPalette(pe1);
        ui.label_10->setPalette(pe1);
        break;
    default:
        break;
    }
    ui.label_pnum->setText("生产者数量:" + QString::number(16 - PSTime / 100));
    ui.label_cnum->setText("消费者数量:" + QString::number(16 - CSTime / 100));
}

OSWork_1::OSWork_1()
    : QMainWindow()
{
    ui.setupUi(this);
    this->setWindowTitle("生产者消费者模拟器");
    producer = nullptr;
    consumer = nullptr;
    //设置黑底红字
    pe1.setColor(QPalette::Background, Qt::black);
    pe1.setColor(QPalette::WindowText, Qt::red);
    pe2.setColor(QPalette::Background, Qt::white);
    pe2.setColor(QPalette::WindowText, Qt::red);
    //ui.label_1->setPalette(pe1);
    connect(producer, &Producer::pro, this, &OSWork_1::display);
    connect(consumer, &Consumer::con, this, &OSWork_1::display);
    connect(ui.pushButton_end, &QPushButton::clicked, this, &OSWork_1::End);
    connect(ui.pushButton_start, &QPushButton::clicked, this, &OSWork_1::ReStart);
    connect(ui.pushButton_addp, &QPushButton::clicked, this, &OSWork_1::add_p);
    connect(ui.pushButton_subp, &QPushButton::clicked, this, &OSWork_1::sub_p);
    connect(ui.pushButton_addc, &QPushButton::clicked, this, &OSWork_1::add_c);
    connect(ui.pushButton_subc, &QPushButton::clicked, this, &OSWork_1::sub_c);
}

OSWork_1::~OSWork_1() {
    End();
}

void OSWork_1::End() {
    if (producer && !producer->m_stop) {
        producer->m_stop = true;
        producer->wait();
        delete producer;
        producer = nullptr;
    }
    if (consumer && !consumer->m_stop) {
        consumer->m_stop = true;
        consumer->wait();
        consumer->quit();
        delete consumer;
        consumer = nullptr;
    }
}

void OSWork_1::ReStart() {
    if (!producer) {
        producer = new Producer;
        connect(producer, &Producer::pro, this, &OSWork_1::display);
        producer->start();
    }
    if (!consumer) {
        consumer = new Consumer;
        connect(consumer, &Consumer::con, this, &OSWork_1::display);
        consumer->start();
    }
}

void OSWork_1::add_p() {
    if (producer) {
        if (PSTime > 600)
            PSTime -= 100;
        qDebug() << "PSTime时长为:" << PSTime;
    }
}

void OSWork_1::sub_p() {
    if (producer) {
        if (PSTime < 1500)
            PSTime += 100;
        qDebug() << "PSTime时长为:" << PSTime;
    }
}

void OSWork_1::add_c() {
    if (consumer) {
        if (CSTime > 600)
            CSTime -= 100;
        qDebug() << "CSTime时长为:" << CSTime;
    }
}

void OSWork_1::sub_c() {
    if (consumer) {
        if (CSTime < 1500)
            CSTime += 100;
        qDebug() << "CSTime时长为:" << CSTime;
    }
}
```java
//PandC.cpp
#include "PandC.h"
using namespace std;
class OSWork_1;
deque<int> q;
mutex mu;
condition_variable cond;
int c = 0;//缓冲区的产品个数
extern int PSTime = 1100;
extern int CSTime = 1100;
int hcnum = 10;
void Producer::run() {
	int data1;
	while (!m_stop) {//通过外层循环,能保证生成用不停止
		if (c < hcnum) {//限流
			{
				data1 = rand();
				unique_lock<mutex> locker(mu);//锁
				q.push_front(data1);
				qDebug() << "存了" << data1 << endl;
				if (c == 1)
					cond.notify_one(); // 通知取
				++c;
			}
			emit pro(c);
			Sleep(PSTime);
		}
	}
}

void Consumer::run() {
	int data2;//data用来覆盖存放取的数据
	while (!m_stop) {
		{
			unique_lock<mutex> locker(mu);
			if (q.empty())
				cond.wait(locker); //wati()阻塞前先会解锁,解锁后生产者才能获得锁来放产品到缓冲区;生产者notify后,将不再阻塞,且自动又获得了锁。
			data2 = q.back();//取的第一步
			q.pop_back();//取的第二步
			qDebug() << "取了" << data2 << endl;
			--c;
		}
		emit con(c);
		Sleep(CSTime);
	}
}
//main.cpp
#include "OSWork_1.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    OSWork_1 w;
    w.show();
    return a.exec();
}

源代码下载地址

CSDN下载链接:https://download.csdn.net/download/myf_666/86245828
github下载链接:https://github.com/ManYufei888/Producer-consumer-process-simulation/tree/main

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherries Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值