zoukankan      html  css  js  c++  java
  • 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目的是保护一个对象,数据结构或者一段代码以至于同一时间只能有一个线程访问。

    宣言:在此记录自己学习过程中的心得体会,同时积累经验,不断提高自己! 文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。 欢迎大家留言交流。转载请注明出处。
  • 相关阅读:
    48. Rotate Image
    83. Remove Duplicates from Sorted List
    46. Permutations
    HTML5笔记
    18. 4Sum
    24. Swap Nodes in Pairs
    42. Trapping Rain Water
    Python modf() 函数
    Python min() 函数
    Python max() 函数
  • 原文地址:https://www.cnblogs.com/vegetable/p/6653930.html
Copyright © 2011-2022 走看看