• Qt线程的简单使用(三)——通过一个实例理解QMutex的使用


    参考资料:实例来源  Qt编程快速入门

    Qt帮助手册关于QMutex、QThread等

    首先先看一个示例,(示例程序来自,Qt编程快速入门,我做了一些修改)。效果图如下,程序开启了三个绘图线程分别往QImage上绘制三角形、圆和矩形。

    主程序中开启了一个定时器,会定时将图片清空。除此主程序的paintEvent事件中,将这个图片通过QPainter绘制显示出来。在绘图线程中,当对QImage操作时,就需要进行加锁,以保证同时只有一个线程可以对QImage进行操作。

    绘图线程的代码。

     1 #ifndef DRAWTHREADING_H
     2 #define DRAWTHREADING_H
     3 #include <QThread>
     4 #include <QWidget>
     5 #include <QMutex>
     6 class DrawThread:public QThread
     7 {
     8     Q_OBJECT
     9 public:
    10     explicit  DrawThread(QWidget *parent = 0);
    11     void SetShape(int inputshape);
    12 protected:
    13     void run();
    14 private:
    15     int shape;
    16 };
    17 
    18 #endif // DRAWTHREADING_H
     1 #include "drawthreading.h"
     2 
     3 #include <QTime>
     4 #include <QImage>
     5 #include <QPainter>
     6 #include "mainwindow.h"
     7 
     8 DrawThread::DrawThread(QWidget *parent):QThread(parent)
     9 {
    10     shape = 0;
    11     QTime tm;
    12     tm = QTime::currentTime();
    13     qsrand(tm.msec());
    14 }
    15 void DrawThread::SetShape(int inputshape)
    16 {
    17     shape = inputshape;
    18 }
    19 void DrawThread::run()
    20 {
    21     QImage* parentScene = ((MainWindow*)(this->parent()))->m_image;
    22 
    23     while(true)
    24     {
    25         int x,y;
    26         x = qrand()% parentScene->width();
    27         y = qrand()% parentScene->height();
    28         int r,g,b;
    29         r = qrand() % 255;
    30         g = qrand() % 255;
    31         b = qrand() % 255;
    32         ((MainWindow*)(this->parent()))->painterLock.lock();
    33         QPainter painter;
    34         painter.begin(parentScene);
    35         QPen m_pen(QColor(r,g,b));
    36         painter.setPen(m_pen);
    37         switch(shape)
    38         {
    39             case 0:
    40             painter.drawEllipse(x,y,(qrand() % 10) * 10,(qrand() % 10) * 10);
    41             break;
    42         case 1:
    43             painter.drawRect(qrand() % parentScene ->width(),qrand() % parentScene->height(),(qrand()%10)* 15,(qrand()%10)* 15);
    44             break;
    45          case 2:
    46             painter.drawLine(x-50,y,x+50,y);
    47             painter.drawLine(x-50,y,x,y- 50);
    48             painter.drawLine(x,y-50,x + 50,y);
    49           default:
    50             break;
    51         }
    52         painter.end();
    53         ((MainWindow*)(this->parent()))->painterLock.unlock();
    54          ((MainWindow*)(this->parent()))->update();
    55         this->msleep(100);
    56     }
    57 }

    注意在run()函数中,当对QImage操作时,使用到QMutex对象的lock,当绘图完成之后进行unlock()。

    主工程代码:

     1 #ifndef MAINWINDOW_H
     2 #define MAINWINDOW_H
     3 #include "ui_mainwindow.h"
     4 #include <QMainWindow>
     5 
     6 namespace Ui {
     7 class MainWindow;
     8 }
     9 #include"drawthreading.h"
    10 #include <QMutex>
    11 class MainWindow : public QMainWindow
    12 {
    13     Q_OBJECT
    14 
    15 public:
    16     explicit MainWindow(QWidget *parent = 0);
    17     ~MainWindow();
    18 
    19 private:
    20    Ui::MainWindow ui;
    21 public:
    22     DrawThread drawTriangleThread;
    23     DrawThread drawEcllipseThread;
    24     DrawThread drawRectThread;
    25     QImage* m_image;
    26     QMutex painterLock;
    27     void paintEvent(QPaintEvent*);
    28     void timerEvent(QTimerEvent* event);
    29 };
    30 
    31 #endif // MAINWINDOW_H
     1 #include "mainwindow.h"
     2 #include "ui_mainwindow.h"
     3 #include <QThread>
     4 #include <QImage>
     5 #include <QPainter>
     6 MainWindow::MainWindow(QWidget *parent) :
     7     QMainWindow(parent)
     8 {
     9     ui.setupUi(this);
    10     this->setAutoFillBackground(true);
    11     m_image = new QImage(1024,768,QImage::Format_RGB32);
    12     QPainter painter(m_image);
    13     QBrush fillBrush(QColor(255,255,255));
    14 
    15    painter.fillRect(0,0,1024,768,fillBrush);
    16     this->startTimer(10000);
    17 
    18     drawEcllipseThread.SetShape(0);
    19     drawEcllipseThread.setParent(this);
    20     drawEcllipseThread.start();
    21 
    22     drawRectThread.SetShape(1);
    23     drawRectThread.setParent(this);
    24     drawRectThread.start();
    25 
    26     drawTriangleThread.SetShape(2);
    27     drawTriangleThread.setParent(this);
    28     drawTriangleThread.start();
    29 }
    30 
    31 MainWindow::~MainWindow()
    32 {
    33     
    34     if (drawEcllipseThread.isRunning())
    35     {
    36         drawEcllipseThread.quit();
    37         drawEcllipseThread.wait();
    38     }
    39     if (drawRectThread.isRunning())
    40     {
    41         drawRectThread.quit();
    42         drawRectThread.wait();
    43     }
    44     if (drawTriangleThread.isRunning())
    45     {
    46         drawTriangleThread.quit();
    47         drawTriangleThread.wait();
    48     }
    49     if (m_image)
    50     {
    51         delete m_image;
    52         m_image = NULL;
    53     }    
    54 }
    55 
    56 void MainWindow::paintEvent(QPaintEvent*)
    57 {
    58     QPainter painter(this);
    59     painter.drawImage(0,0,*m_image);
    60 
    61 }
    62 void MainWindow::timerEvent(QTimerEvent* event)
    63 {
    64     QPainter painter(m_image);
    65     QBrush fillBrush(QColor(255,255,255));
    66     painter.fillRect(0,0,1024,768,fillBrush);
    67 }

    我们在Qt帮助中查看QMutex,

    The QMutex class provides access serialization between threads.

    The purpose of a QMutex is to protect an object, data structure or section of code so that only one thread can access it at a time (this is similar to the Java synchronized keyword). It is usually best to use a mutex with a QMutexLocker since this makes it easy to ensure that locking and unlocking are performed consistently.

    翻译过来,大致意思是,QMutex提供提供线程之间访问顺序化。QMutex目的是保护一个对象,数据结构或者一段代码以至于同一时间只能有一个线程访问。(与java中的关键字synchroized的类似)。Qt中的建议是使用QMutexLocker代替QMutex为了更容易的加锁、解锁。使用QMutexLocker对以上的代码进行调整,如下:

    void DrawThread::run()
    {
        QImage* parentScene = ((MainWindow*)(this->parent()))->m_image;
    
        //注意这里,使用QMutexLocker
        QMutexLocker locker(&((MainWindow*)(this->parent()))->painterLock);
        while(true)
        {
            int x,y;
            x = qrand()% parentScene->width();
            y = qrand()% parentScene->height();
            int r,g,b;
            r = qrand() % 255;
            g = qrand() % 255;
            b = qrand() % 255;
            //((MainWindow*)(this->parent()))->painterLock.lock();
            QPainter painter;
            painter.begin(parentScene);
            QPen m_pen(QColor(r,g,b));
            painter.setPen(m_pen);
            switch(shape)
            {
                case 0:
                painter.drawEllipse(x,y,(qrand() % 10) * 10,(qrand() % 10) * 10);
                break;
            case 1:
                painter.drawRect(qrand() % parentScene ->width(),qrand() % parentScene->height(),(qrand()%10)* 15,(qrand()%10)* 15);
                break;
             case 2:
                painter.drawLine(x-50,y,x+50,y);
                painter.drawLine(x-50,y,x,y- 50);
                painter.drawLine(x,y-50,x + 50,y);
              default:
                break;
            }
            painter.end();
            //((MainWindow*)(this->parent()))->painterLock.unlock();
             ((MainWindow*)(this->parent()))->update();
            this->msleep(100);
        }
    }

    至此,QMutex的方法已经讲诉完了,总之,QMutex提供提供线程之间访问顺序化。QMutex目的是保护一个对象,数据结构或者一段代码以至于同一时间只能有一个线程访问。

    宣言:在此记录自己学习过程中的心得体会,同时积累经验,不断提高自己! 文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。 欢迎大家留言交流。转载请注明出处。
  • 相关阅读:
    前端面试题
    js collection
    javascript变量声明提升(hoisting)
    css3动画
    神奇的meta
    wap站bug小结
    前端collection
    js拾遗
    prototype之初印象
    自定义scrollBottom的值
  • 原文地址:https://www.cnblogs.com/vegetable/p/6653930.html
Copyright © 2020-2023  润新知