作者:非妃是公主
专栏:《操作系统》
个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩
专栏地址
专栏系列文章
需求规格说明
基于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
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/130526.html