作者saladim (杀拉顶)
看板C_and_CPP
标题[问题] QT在大量计算时同时更新Widget
时间Mon Sep 11 01:49:12 2017
开发平台(Platform): (Ex: Win10, Linux, ...)
Linux
编译器(Ex: GCC, clang, VC++...)+目标环境(跟开发平台不同的话需列出)
GCC
额外使用到的函数库(Library Used): (Ex: OpenGL, ...)
QT 4.X
问题(Question):
目前有一个应用程式, 里面有一个大量计算的部分(至少20分钟).
此应用程式使QT, 此大量计算的部分在main thread里面. 这是因为这个程式已经很老了
後来转用QT, 但是整个架构若是要改, 会动到很底层很多东西,
所以就没有重整了 ORZ.
问题来了, 当进入大量计算时, 程式的GUI会没有反应且会"灰掉", 不论移动视窗或是
按钮都没有反应, 所以无法得知程式是死掉hang住了 还是正在计算中.
所以想用progressbar或是类似动画的东西来至少表示程式还活着,
可是都无法成功, 试过的方法如下:
以下都以progressbar为例, 其他的像是动画也是差不多结果
1. 使用QObject的Timer或是 QTimer的timer event
==> 失败, 所有的timer event都在计算完毕才进来
2. 起一个QThread, 使用连接Signal-Slot的方式来更新(定时emit signal)
==> 毫无效果. 对於连接Singal-Slot时的最後一个参数(enum Qt::ConnectionType),
试过所有种类
3. 起另一个QThread, 在run()里面起另一个event loop, 然後使用timer
再call progressbar的update() (progressbar不论在主thread或是
另外的thread结果一样)
==> 无效 (timer有发挥效果, 只是无法更新)
4. 起另一个std::thread, call update()
==> 无效
5. 在主thread使用Linux Signal Handler, 在signal handler里面更新进度并call
update() 或是call processEvent()让QT去处理在Queue里面的event.
而signal是由另外一个thread发出.
==> 可行, 但是QT的processEvent/update()会用到malloc, 会产生dead lock.
简单说 这些函式都不是Async-Signal Safe(或是非可重入的)
由以上试验看来, 似乎只能起另外一个process了, 只不过起另外一个process需要
先准备一个执行档, 不知道有没有办法像起thread一样, 可以起一个process来执行某个
函式吗?
请问各位先进, 对於上述遇到的问题是否有解法呢?
看起来, 只要main thread有大量计算, 则所有GUI相关的动作都会因为资源被占走而
延後处理.........难道只能用另一个process吗......
请各位先进不吝解惑!! 感谢!!
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 36.228.226.32
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1505065754.A.27B.html
1F:推 firejox: 把大量计算丢在另个thread? 09/11 02:31
2F:→ saladim: 因为最早根本没有多绪的概念 所以计算部分丢另外一个 09/11 03:06
3F:→ saladim: thread会crash 基础建设都是没有多绪思考 要改会改很大.. 09/11 03:08
4F:→ bluesoul: 计算时,固定的时机点直接呼叫processEvent() 09/11 05:03
5F:→ MOONY135: QProcess吧 09/11 07:45
6F:→ MOONY135: +socket 09/11 07:46
※ 编辑: saladim (36.228.226.32), 09/11/2017 08:29:06
7F:→ longlongint: 把进度印到档案 看档案就知道进度了 09/11 13:23
8F:→ longlongint: 记得 flush 09/11 13:26
9F:→ uranusjr: QtConcurrent 豪豪用 09/11 13:44
10F:推 Bencrie: 计算丢另一个 thread 他还是单 thread 啊 09/11 13:46
11F:→ Bencrie: 这样就要改很大说不过去吧 09/11 13:47
12F:推 Bencrie: 你需要熟悉一下基本视窗程式的原理,不然你不管写什麽 09/11 13:51
13F:→ Bencrie: GUI 程式都会遇到一样的问题 09/11 13:51
14F:推 rodion: 哪里有progress bar不能work的道理?最可能是用哪里错了 09/11 18:02
15F:→ rodion: 先找个progress bar简单范例改改 确认自己真的了解再说 09/11 18:04
16F:→ saladim: 不是说progressbar不能work啦..是说在大量计算下 09/11 20:20
17F:→ saladim: progressbar或是任何GUI都没法"同时"作用 这个行为在 09/11 20:21
18F:→ saladim: C++ GUI programming这本书里面就有说 09/11 20:22
19F:→ saladim: 我几乎没在写GUI 都是写computing engine, 这个应用程式 09/11 20:23
20F:→ saladim: 是建立在一堆单绪思考的老东西上啦 要改等於整个翻新,,, 09/11 20:24
21F:→ saladim: 请各位先进提供一下可能解法阿 XDDDD 09/11 20:26
22F:→ longlongint: 那就偷插 sleep 或是给 process 安个 nice 阿 XD 09/11 21:01
23F:推 Killercat: GUI thread是最不该碰的东西啊.... 09/11 21:58
24F:→ stucode: 我觉得你应该是把 GUI 跟大量计算的程式码通通混在一起了 09/11 23:25
25F:→ stucode: 先想办法把两者拆开,问题才有办法从根本解决。 09/11 23:25
26F:→ stucode: 不然任何方案都有一堆地雷等你踩。 09/11 23:25
27F:推 chuchunn: 第二个方法是对的,不行的话可能是QThread建立的方式错误 09/12 15:04
28F:→ chuchunn: 或是QThread内有包含gui的内容,或者connect的方式错误 09/12 15:05
29F:推 andyjy12: 如果在main thread做运算还要可以update gui,那要在 09/12 19:13
30F:→ andyjy12: 运算中的thread 加入 qApp->processEvent() 09/12 19:14
31F:→ andyjy12: 然後你2 3的解法,该不会是把GUI 丢去thread吧...? 09/12 19:17
32F:→ saladim: @chuchunn:第二方法主thread计算 另起的那个thread呼叫 09/12 20:38
33F:→ saladim: @chuchunn:update() GUI, 都没作用 所有参数都试过了 09/12 20:38
34F:→ saladim: @andyjy12:不是, 只是呼叫在main thread产生的widge的 09/12 20:40
35F:→ saladim: 的member function(也就是用来更新GUI的那些), 实际上我 09/12 20:40
36F:→ saladim: 也是过在新产生的那个thread里面new过一个progressbar, 09/12 20:41
37F:→ saladim: 结果一样无法同时作用 无法看到有在活动的效果, 计算进度 09/12 20:42
38F:→ saladim: 还算容易知道 也蛮容易传递的 就是GUI动不了 ORZ 09/12 20:42
39F:推 firejox: 如果不去把大量计算放在另一个thread的话,那就把计算切 09/12 21:50
40F:→ firejox: 小块吧。 09/12 21:50
41F:推 Bencrie: 你不能在非 UI mainloop 所在的 thread 呼叫任何会动到 09/12 23:49
42F:→ Bencrie: UI 的函数。 09/12 23:50
43F:推 chuchunn: 应该是新增的thread去做运算,并在运算的过程发送signal 09/13 11:52
44F:→ chuchunn: 再由原本的thread进行更新的动作 09/13 11:54
45F:→ saladim: 感谢各位意见.看来只能重整或是另个process了..感谢大家 09/15 00:30