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目的是保護一個對象,數據結構或者一段代碼以至於同一時間只能有一個線程訪問。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM