第12章:QMutex

1,信号的互斥QMutex

2,源码:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMutex>
#include <QMutexLocker>
#include <QThread>
#include <stdio.h>
#include <QCoreApplication>
#include <QSemaphore>

//前置类型声明只能作为指针或者引用,不能定义类的对象,所以也不能调用对象中的方法
class Producer;
class Consumer;

namespace Ui {
class MainWindow;
}


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
    void ReceiveText(QString str);

private slots:
    void on_startButton_clicked();

    void on_stopButton_clicked();

    void on_quitButton_clicked();

private:
    Ui::MainWindow *ui;

    Producer *producer;
    Consumer *consumer;
};




class KEY
{
public:
    KEY() {key = 0;}
    int creatKey() {mutex.lock(); ++key; return key; mutex.unlock();}           //使用mutex进行互斥操作,但是unlock()却在return之后
    int value()    {mutex.lock();        return key; mutex.unlock();}           //从而导致unlock()操作永远无法执行

private:
    int    key;
    QMutex mutex;
};



class NewKEY
{
public:
    NewKEY() {key = 0;}
    int creatKey() { QMutexLocker locker(&mutex); ++key; return key;}           //QMutexLocker类可以简化互斥量的处理
    int value()    { QMutexLocker locker(&mutex);        return key;}           //lokcer()函数作为局部变量会在函数退出时结束其作用域,从而自动对互斥量mutex解锁

private:
    int    key;
    QMutex mutex;
};




//信号量的生产者和消费者
class Producer: public QThread
{
    Q_OBJECT

public:
    Producer();
    void run();
};


class Consumer: public QThread
{
    Q_OBJECT

public:
    Consumer();
    void run();

signals:
    void sendText(QString str);

};
#include "mainwindow.h"
#include "ui_mainwindow.h"

const int DataSize   = 1000;
const int BufferSize = 80;
int       buffer[BufferSize];         //首先生产者向buffer中写入数据,直到它到达终点,然后从起点重新开始覆盖已经存在的数据

QSemaphore freeBytes(BufferSize);     //freeBytes信号量控制可被生产者填充的缓冲区部分,被初始化为BufferSize(80), 表示程序一开始有BufferSize个缓冲区单元可被填充
QSemaphore usedBytes(0);              //usedBytes信号量控制可被消费者读取的缓冲区部分,被初始化为0,表示程序一开始时缓冲区中没有数据可供读取


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    producer = new Producer;
    consumer = new Consumer;
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::ReceiveText(QString str)
{
    ui->textEdit->insertPlainText(str);
    ui->textEdit->insertPlainText("\n");
}




void MainWindow::on_startButton_clicked()
{
   if ( !producer->isRunning())
   {
        producer->start();
   }

   if (!consumer->isRunning())
   {
        consumer->start();
        connect(consumer, SIGNAL(sendText(QString)), this, SLOT(ReceiveText(QString)));
   }
}

void MainWindow::on_stopButton_clicked()
{
    producer->terminate();
    producer->wait();

    disconnect(consumer, SIGNAL(sendText(QString)), this, SLOT(ReceiveText(QString)));
    consumer->terminate();
    consumer->wait();
}

void MainWindow::on_quitButton_clicked()
{
    ui->textEdit->clear();
}






//生产者
Producer::Producer()
{

}

void Producer::run()
{
    for (int i=0; i<DataSize; i++)
    {
        freeBytes.acquire();                       //生产者线程首先获取一个空闲单元,如果此时缓冲区被消费者尚未读取的数据填满
                                                   //对此函数的调用就会阻塞,直到消费者读取了这些数据
                                                   //acquire(n)函数用于获取n个资源,当没有足够的资源时调用者将被阻塞直到足够的可用资源
        buffer[i%BufferSize] = (i%BufferSize);     //一旦生产者获取了某个空闲单元,就使用当前的缓冲区单元序号填写这个缓冲区单元
        usedBytes.release();                       //调用该函数将可用资源加1,表示消费者此时可以读取这个刚刚填写的单元
                                                   //release(n)函数用于释放n个资源
    }
}



//消费者
Consumer::Consumer()
{

}


void Consumer::run()
{
    QString str = "";
    for (int i=1; i<DataSize; i++)
    {
        usedBytes.acquire();                         //消费者线程首先获取一个可被读取的单元,如果缓冲区中没有包含任何可以读取的数据
                                                     //对此函数的调用就会阻塞,直到生产者生产了一些数据

        str += QString("%1").arg(buffer[i%BufferSize], 2, 10, QLatin1Char(' '));
        str += " ";
        if ((i%15 == 0) && (i != 0))
        {
            str += "\n";
            emit sendText(str);
            str = "";
        }

        freeBytes.release();
    }
}

3,效果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ksmtnsv37297/article/details/86674494
今日推荐