[问题] QT在大量计算时同时更新Widget

楼主: saladim (杀拉顶)   2017-09-11 01:49:12
开发平台(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吗......
请各位先进不吝解惑!! 感谢!!
作者: firejox (Tangent)   2017-09-11 02:31:00
把大量计算丢在另个thread?
楼主: saladim (杀拉顶)   2017-09-11 03:06:00
因为最早根本没有多绪的概念 所以计算部分丢另外一个thread会crash 基础建设都是没有多绪思考 要改会改很大..
作者: bluesoul (忙死你老爸)   2017-09-11 05:03:00
计算时,固定的时机点直接呼叫processEvent()
作者: MOONY135 (谈无欲)   2017-09-11 07:45:00
QProcess吧+socket
作者: longlongint (华哥尔)   2017-09-11 13:23:00
把进度印到档案 看档案就知道进度了记得 flush
作者: uranusjr (←這人是超級笨蛋)   2017-09-11 13:44:00
QtConcurrent 豪豪用
作者: Bencrie   2017-09-11 13:46:00
计算丢另一个 thread 他还是单 thread 啊这样就要改很大说不过去吧你需要熟悉一下基本视窗程式的原理,不然你不管写什么GUI 程式都会遇到一样的问题
作者: rodion (r-kan/reminder)   2017-09-11 18:02:00
哪里有progress bar不能work的道理?最可能是用哪里错了先找个progress bar简单范例改改 确认自己真的了解再说
楼主: saladim (杀拉顶)   2017-09-11 20:20:00
不是说progressbar不能work啦..是说在大量计算下progressbar或是任何GUI都没法"同时"作用 这个行为在C++ GUI programming这本书里面就有说我几乎没在写GUI 都是写computing engine, 这个应用程式是建立在一堆单绪思考的老东西上啦 要改等于整个翻新,,,请各位先进提供一下可能解法阿 XDDDD
作者: longlongint (华哥尔)   2017-09-11 21:01:00
那就偷插 sleep 或是给 process 安个 nice 阿 XD
作者: Killercat (杀人猫™)   2017-09-11 21:58:00
GUI thread是最不该碰的东西啊....
作者: stucode   2017-09-11 23:25:00
我觉得你应该是把 GUI 跟大量计算的程式码通通混在一起了先想办法把两者拆开,问题才有办法从根本解决。不然任何方案都有一堆地雷等你踩。
作者: chuchunn   2017-09-12 15:04:00
第二个方法是对的,不行的话可能是QThread建立的方式错误或是QThread内有包含gui的内容,或者connect的方式错误
作者: andyjy12 (??)   2017-09-12 19:13:00
如果在main thread做运算还要可以update gui,那要在运算中的thread 加入 qApp->processEvent()然后你2 3的解法,该不会是把GUI 丢去thread吧...?
楼主: saladim (杀拉顶)   2017-09-12 20:38:00
@chuchunn:第二方法主thread计算 另起的那个thread呼叫@chuchunn:update() GUI, 都没作用 所有参数都试过了@andyjy12:不是, 只是呼叫在main thread产生的widge的的member function(也就是用来更新GUI的那些), 实际上我也是过在新产生的那个thread里面new过一个progressbar,结果一样无法同时作用 无法看到有在活动的效果, 计算进度还算容易知道 也蛮容易传递的 就是GUI动不了 ORZ
作者: firejox (Tangent)   2017-09-12 21:50:00
如果不去把大量计算放在另一个thread的话,那就把计算切小块吧。
作者: Bencrie   2017-09-12 23:49:00
你不能在非 UI mainloop 所在的 thread 呼叫任何会动到UI 的函数。
作者: chuchunn   2017-09-13 11:52:00
应该是新增的thread去做运算,并在运算的过程发送signal再由原本的thread进行更新的动作
楼主: saladim (杀拉顶)   2017-09-15 00:30:00
感谢各位意见.看来只能重整或是另个process了..感谢大家

Links booklink

Contact Us: admin [ a t ] ucptt.com