QThread的常见特性:

  run()是线程的入口,就像main()对于应用程序的作用。QThread中对run()的默认实现调用了exec(),从而创建一个QEventLoop对象,由其处理该线程事件队列(每一个线程都有一个属于自己的事件队列)中的事件。简单用代码描述如下:

 1 int QThread::exec()
2 {
3 //...
4 QEventLoop eventLoop;
5 int returnCode = eventLoop.exec();
6 //...
7 return returnCode;
8 }
9
10 int QEventLoop::exec(ProcessEventsFlags flags)
11 {
12 //...
13 while (!d->exit) {
14 while (!posted_event_queue_is_empty) {
15 process_next_posted_event();
16 }
17 }
18 //...
19 }

  由此可见,exec()在其内部不断做着循环遍历事件队列的工作,调用QThread的quit()或exit()方法使停止工作,尽量不要使用terminate(),该方法过于粗暴,造成资源不能释放,甚至互斥锁还处于加锁状态。

1.旧的使用方式:

  这是qt4.6及之前的使用方法,这种方式本没有什么错误,可以处理我们的绝大多数需求。Thread对象本身工作在主线程下,即使调用的t.stop()方法,它也是工作在主线程下,只有run()范围内的代码工作在次线程中。

 1 class WorkerThread : public QThread
2 {
3 Q_OBJECT
4
5 void run() Q_DECL_OVERRIDE {
6 QString result;
7 emit resultReady(result); // 只发射信号,去真正的业务内容
8 }
9
10 signals:
11 void resultReady(const QString &s);
12 };
13
14 void MyObject::startWorkInAThread()
15 {
16 WorkerThread *workerThread = new WorkerThread(this);
17 connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
18 connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
19 workerThread->start();
20 }

  从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater()。

2.推荐的使用方式:

  这是Qt4.7及以后版本推荐的工作方式。其主要特点就是利用Qt的事件驱动特性,将需要在次线程中处理的业务放在独立的模块(类)中,由主线程创建完该对象后,将其移交给指定的线程,且可以将多个类似的对象移交给同一个线程。在这个例子中,信号由主线程的QTimer对象发出,之后Qt会将关联的事件放到worker所属线程的事件队列。由于队列连接的作用,在不同线程间连接信号和槽是很安全的。
说说connect最后一个参数,连接类型:
1)自动连接(AutoConnection),默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接受者处在不同线程,等同于队列连接。
2)直接连接(DirectConnection),当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行。

3)队列连接(QueuedConnection),当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行。

 1 class Worker : public QObject
2 {
3 Q_OBJECT
4
5 public slots:
6 void doWork(const QString meter) {
7 // ...
8 emit resultReady(result);
9 }
10 void stopWork(){
11 //...
12 }
13 signals:
14 void resultReady(const QString &result);
15 };
16
17 class Controller : public QObject
18 {
19 Q_OBJECT
20
21 QThread workerThread;
22
23 public:
24 Controller() {
25 Worker *worker = new Worker;
26 worker->moveToThread(&workerThread);
27 connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);
28 connect(this, &Controller::operate, worker, &Worker::doWork);
29 connect(this, &Controller::kill, worker, &Worker::stopWork);
30 connect(worker, &Worker::resultReady, this, &Controller::handleResults);
31 workerThread.start();
32 }
33 ~Controller() {
34 workerThread.quit();
35 workerThread.wait();
36 }
37
38 public slots:
39 void handleResults(const QString &);
40
41 signals:
42 void operate(const QString &);
43 void kill();
44 };
 

  使用新方式,子线程中的槽都在子线程中运行,主线程中的槽都在主线程中运行,信号和槽默认使用自动连接(AutoConnection)。值得注意的是,如果槽doWork中有耗时操作,比如说while循环,主线程的信号kill子线程是不会响应的,除非使用直接连接(DirectConnection),connect(this, &Controller::kill, worker, &Worker::stopWork, Qt::DirectConnection);,此时,槽stopWork工作于主线程。

3.GUI界面假死的处理
  在GUI程序中,主线程也叫GUI线程,因为它是唯一被允许执行GUI相关操作的线程。对于一些耗时的操作,如果放在主线程中,就是出现界面无法响应的问题。这种问题的解决一种方式是,把这些耗时操作放到次线程中,还有一种比较简单的方法:在处理耗时操作中频繁调用QApplication::processEvents()。这个函数告诉Qt去处理那些还没有被处理的各类事件,然后再把控制权返还给调用者。

 
http://www.cnblogs.com/georgeOfChina/p/8143484.html

Qt多线程和GUI界面假死(run()是线程的入口,就像main()对于应用程序的作用。分析QThread::exec函数的源码,旧的QMutexLocker模式其实很好用,挡住别人进入抢占资源,可照抄)good的更多相关文章

  1. WinForm多线程+委托防止界面假死

    当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决 using System; using System.Collections.Generic ...

  2. WinForm程序界面假死,寻求完美解决方案

    故事的开端是这样的,小白是一个程序员,他确实也是一个小白,目前还在程序员发展的道路上,兢兢业业的小心求学. 有一天,小白接到一个任务,完成一个Winform程序,附加一个功能就是可以读IC卡. 小白终 ...

  3. C# Winform 窗体界面”假死”后台线程阻塞 解决办法–BeginInvoke

    原文:C# Winform 窗体界面"假死"后台线程阻塞 解决办法–BeginInvoke 这个方法可以用在任何后台任务耗时较长,造成界面“假死”界面控件不更新的情况. 比如要要执 ...

  4. WinForm查询大数据界面假死,使用异步调用解决

    用DataGridView无分页绑定一个几千条数据的查询,查询的时候界面直接卡死十几秒,用户体验非常不好,因此用异步操作解决界面卡死的问题原本场景:点击[查询]后,界面直接卡死优化场景:点击[查询]后 ...

  5. C#中异步及winform中界面假死

    c#中可以用BeginInvoke去启动异步调用,但是有两个BeginInvoke一个是controller的BeginInvoke还有一个是委托的BeginInvoke. 主要区别是controll ...

  6. 解决c# progressBar更新出现界面假死

    最近一个项目需求中的一个功能是需要用progressBar反映处理文件的进度. 研究了Invoke和BeginInvoke方法. Control.Invoke 方法 (Delegate) :在拥有此控 ...

  7. 使用publisher模式控制频繁的UI输出,避免Winform界面假死

    http://www.cnblogs.com/Charltsing/p/publisher.html 最近测试task并发任务的效率与线程池的区别,发现了另外一个问题.task建立任务的速度很快,输出 ...

  8. qt开发ROS gui界面环境配置过程总结

    这段时间花了点时间配置了在qtcreator5.9.1上开发ros gui界面的环境,终于可以实现导入工程,插断点调试了.总结起来需要注意以下几点: 1.安装插件ros_qtc_plugin,ROS与 ...

  9. WPF界面假死

    首先要检查那些滥用 Timer.Dispacher Timer 或者滥用什么“线程+死循环+阻塞”轮询的代码. 这种是编程大忌,有些人不会设计事件驱动程序,而是滥用轮询. 若是:触发事件后的假死,搜W ...

随机推荐

  1. 【CS Round #46 (Div. 1.5) E】Ultimate Orbs

    [链接]链接 [题意] n个人从左到右站在一条直线上.每个人都有一个能力值g[i],然后每个人可以将相邻的一个人打败. 然后它的能力值能够增加相应的能力值(就是打败了的那个人的能力值). A能够打败B ...

  2. 百度2019校招Web前端工程师笔试卷(9月14日)

    8月27日晚,在实习公司加班.当时正在调试页面,偶然打开百度首页console,发现彩蛋,于是投了简历. 9月14日晚,七点-九点,在公司笔试. 笔试题型(有出入): 一.单选20道 1.难度不难,考 ...

  3. 11.3 Android显示系统框架_最简单的surface测试程序

    APP有一个surface(界面),其有多个buffer用来存放界面数据,这些buffer是向surfaceflinger申请的: 因此我们编写的surface测试程序步骤: (1)获得surface ...

  4. HDU 2147kiki's game

    KIKI和zz一起玩跳棋游戏,KIKI先.跳棋棋盘有n行m列.在顶行的最右侧位置放上一枚硬币.每次每个人可以把硬币移动到左边,下边或是左下边的空格中.最后不能移动硬币的那个人将输掉比赛. P点:即必败 ...

  5. [WASM] Write to WebAssembly Memory from JavaScript

    We write a function that converts a string to lowercase in WebAssembly, demonstrating how to set the ...

  6. 等价变换(equivalent transformation)

    1. 加加减减 (x−b)n=(x−a+a−b)n=∑i=0n(ni)(x−a)i(a−b)n−i

  7. 【z08】乌龟棋

    描述 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点 ...

  8. Hbase常见异常 分类: B7_HBASE 2015-02-02 16:16 412人阅读 评论(0) 收藏

    1. HBase is able to connect to ZooKeeper but the connection closes immediately hbase(main):001:0> ...

  9. js进阶解决浏览器缓存不能自动更新的问题(在ajax的url上带上一个参数,可以是日期,或者是随机数)(随机数Math.random)(取得日期的毫秒数:new Date().getTime();)

    js进阶解决浏览器缓存不能自动更新的问题(在ajax的url上带上一个参数,可以是日期,或者是随机数)(随机数Math.random)(取得日期的毫秒数:new Date().getTime();) ...

  10. crx 【 集合 】

    Vimium dbepggeogbaibhgnhhndojpepiihcmeb-1.64-Crx4Chrome.com.crx https://www.crx4chrome.com/down/731/ ...