从一个实例来看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目的是保护一个对象,数据结构或者一段代码以至于同一时间只能有一个线程访问。

时间: 2024-12-25 23:27:12

从一个实例来看QMutex的使用的相关文章

Java程序只运行一个实例[转]

如果希望你的Java程序只能存在一个实例,可以参考下面的用法. 原文链接:http://blog.csdn.net/yaerfeng/article/details/7264729 Java没有提供这样的机制.从操作系统的观点来看,一个启动的Java Application仅仅是一个JVM的运行实例.运行相同Application的两个实例,仅仅是运行两个无关的JVM.       只有让多个运行实例之间有一个既定的通讯机制就可以保证只有一个实例运行. 方案1:使用Java的加锁文件机制,ide

Python使用MySQL数据库的方法以及一个实例

使用环境:Windows+python3.4+MySQL5.5+Navicat 一.创建连接 1.准备工作,想要使用Python操作MySQL,首先需要安装MySQL-Python的包,在Python 3.x下,该包已经改名为MySQLClient.可以使用pip方式安装: pip install MySQLClient 或者下载包文件,进行安装也可以. 2.Python使用MySQL的流程: 3.启动MySQL服务器:以管理员身份启动“cmd”,输入命令:’net start mysql‘ P

只运行一个实例以及内存泄漏检测

unit 使应用程序只运行一个实例; interface uses Windows; const  // - 互斥体唯一的名字  _Mutex_Name = '{19631971-1976-1981-1989-199319941995}'; var  _Mutex_Handle: THandle; implementation initialization // - 载入时调用的代码 // - 创建互斥体对象_Mutex_Handle := CreateMutex(nil, False, LPC

C# WinForm 判断程序是否已经在运行,且只允许运行一个实例

static class Program {   /// <summary>   /// 应用程序的主入口点.   /// </summary>   [STAThread]   static void Main()   {     Application.EnableVisualStyles();     Application.SetCompatibleTextRenderingDefault(false);     //1.这里判定是否已经有实例在运行     //只运行一个实

转 C# 只允许运行一个实例

来源:http://blog.csdn.net/jin20000/article/details/3136791 互斥进程(程序), 简单点说,就是在系统中只能有该程序的一个实例运行. 现在很多软件都有这功能,如Maxthon 可以设置为"只允 许打开一个窗体",还有Bitcomet等. 我也是看到这些软件的这个功能才来研究这个问题的.  要实现程序的互斥,通常有三中方式,下面 用 C#  语言来实现: 实现方式一: 使用线程互斥变量. 通过定义互斥变量来判断是否已运行实例.C#实现如

C++静态变量本身可否是一个实例对象

一般书上总是用int来举例,那个太简单.如果静态变量本身可否是一个实例对象呢?应该是可以,但是这样涉及到它的构造函数以及它内部的静态变量如何初始化两个问题,换而言之,这个静态变量本身应该如何初始化?这个问题和单例模式有些关系,回头查查. 以下是一个不成熟的例子,但是能编译运行通过. #include "stdafx.h" #include <iostream> using namespace std; class AAA { public: static int sss;

使程序只运行一个实例

//APP 里面 //1.// 此程序只能运行一次,用互斥量来判断程序是否已运行 1 HANDLE m_hMutex=CreateMutex(nullptr,TRUE, m_pszAppName); 2 if(GetLastError()==ERROR_ALREADY_EXISTS) { return FALSE; } //2. 1 HWND hWnd = FindWindow(nullptr, m_pszAppName/*_T("MyDlg")*/); //第一个参数: 窗口的类名

ArcGIS API for JavaScript开发环境搭建及第一个实例demo

原文:ArcGIS API for JavaScript开发环境搭建及第一个实例demo ESRI公司截止到目前已经发布了最新的ArcGIS Server for JavaScript API v3.9,它提供了更为丰富而又强大的功能.     一.安装前准备 1.ArcGIS Server for JavaScript API各版本下载地址:http://support.esrichina-bj.cn/2011/0223/960.html,我们选择下载最新的"ArcGIS API for Ja

检查一个实例的状态变化

使用情景: 一个实例在上次“保存”操作之后又被修改了,需要检查它的状态变化以便有选择的保存此实例. 解决方案: 一个有效的解决方案是创建一个mixin类,这个类可以从多个类继承并能对一个实例的状态进行快照操作,这样就可以用此实例的当前状态和上次的快照做比较了,来判断是否被修改过了. 1 import copy 2 class ChangeCheckerMixin: 3 containerItems = {dict: dict.iteritems, list: enumerate} 4 immut