• 10182阅读
  • 10回复

[提问]问一个关于QT多线程的问题 [复制链接]

上一主题 下一主题
离线kamatyo
 

只看楼主 倒序阅读 楼主  发表于: 2011-08-28
原先我的程序跑的单线程,由于运算和等待比较长,所以GUI经常假死,想做成多线程

GUI上有多个按钮,实现不同的功能,一次只能运行一个功能。现在所有的功能都在一个类中实现,在不同的按钮事件中调用。

如果做成多线程,是否要把每个功能用单独的类实现一下,继承QThread并重载其run()函数,如此一来需要把原先的类拆成N个类实现,有些麻烦。

像这种情况应该如何设计类呢,是否一定要单独写类才会比较好?谢谢
离线dbzhang800

只看该作者 1楼 发表于: 2011-08-28
离线yzpdsg

只看该作者 2楼 发表于: 2011-08-28
实现一个线程类,然后在需要的地方调用这个类进行运算就可以避免主界面死掉,而且不用每次重新实现。
离线kamatyo

只看该作者 3楼 发表于: 2011-08-28
那是否要重新实现N个类呢?因为有N个地方需要调用,而一个类里只有一个run啊。

另外倒是可以初始化线程类时指明需要执行什么功能,在run里判断并执行相应功能,但感觉不是太舒服,因为不同的功能反应到GUI上的显示是不一样的,所以执行完后会发射不同的信号通知GUI更新。


离线dbzhang800

只看该作者 4楼 发表于: 2011-08-28
引用第3楼kamatyo于2011-08-28 23:11发表的  :
那是否要重新实现N个类呢?因为有N个地方需要调用,而一个类里只有一个run啊。
另外倒是可以初始化线程类时指明需要执行什么功能,在run里判断并执行相应功能,但感觉不是太舒服,因为不同的功能反应到GUI上的显示是不一样的,所以执行完后会发射不同的信号通知GUI更新。
.......

我还是希望你能先看看前面给的链接(特别是第二个表格),翻译后的东西可能不容易理解,你可以直接看英文原文。

题外:
  如果我没有理解错你的意思,你应该用不着子类化QThread,一个都不需要!
离线kamatyo

只看该作者 5楼 发表于: 2011-08-29
回 4楼(dbzhang800) 的帖子
谢谢你,那文档我看了,可能我对多线程理解不够,我认为“使用QThread,重新实现run函数并根据需要发送信号。使用信号槽的queued连接方式将信号连接到GUI线程的槽函数。”这个适合我这种情况,你说的不用子类化QThread,我不太想得通。

我的目前有两个类,UI类和OPERATION类,UI类展现,OP类实现业务逻辑,UI触发事件函数调用OP相应的功能。我打算中间写一个MThread类继承QThread,重载run函数。UI类事件函数生成MThread类并run,run中判断UI调用的是什么功能,再去OP类调用。执行完成后将结果用事件发送回UI进行更新。不知道这么实现是否合理。


离线dbzhang800

只看该作者 6楼 发表于: 2011-08-29
Re:回 4楼(dbzhang800) 的帖子
引用第5楼kamatyo于2011-08-29 09:48发表的 回 4楼(dbzhang800) 的帖子 :
谢谢你,那文档我看了,可能我对多线程理解不够,我认为“使用QThread,重新实现run函数并根据需要发送信号。使用信号槽的queued连接方式将信号连接到GUI线程的槽函数。”这个适合我这种情况,你说的不用子类化QThread,我不太想得通。
我的目前有两个类,UI类和OPERATION类,UI类展现,OP类实现业务逻辑,UI触发事件函数调用OP相应的功能。我打算中间写一个MThread类继承QThread,重载run函数。UI类事件函数生成MThread类并run,run中判断UI调用的是什么功能,再去OP类调用。执行完成后将结果用事件发送回UI进行更新。不知道这么实现是否合理。
.......

如果你的 UI 类和 OPERATION类都是通过事件或信号槽联系的,那么,你这两个类可能都不需要做任何的修改

直接新建一个QThread,然后将OPERATION move到新线程即可。

可以看看这个:http://hi.baidu.com/cyclone/blog/item/5fac3bc7ab1b90d1d10060f2.html
离线kamatyo

只看该作者 7楼 发表于: 2011-08-30
回 6楼(dbzhang800) 的帖子
我看了一下move是把线程无关的类变成线程相关了,并且“Bradley T. Hughes 给出说明是: QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中。”这个正是我想要的效果。

但如果这样,UI层很多参数需要穿过QThread传到OPERATION,我觉得很不爽,QThread做了个二传手。还有在更新数据时必须在OPERATION里emit信号,又是穿过QThread传到UI。数据分层做的很不理想。但其他好像没有办法解决。不知道有没有什么好建议。

注:OPERATION里emit信号是因为OPERATION中的功能需要循环依次得出一些结果,我想把这些结果一个一个地往UI显示,所以只能放到循环内了。本来OPERATION里比较纯的业务逻辑,如此就参入了表现层的东西。如果能把这个放到QThread代理层,可能会更理想些,我有些完美主义
离线dbzhang800

只看该作者 8楼 发表于: 2011-08-30
Re:回 6楼(dbzhang800) 的帖子
引用第7楼kamatyo于2011-08-30 09:11发表的 回 6楼(dbzhang800) 的帖子 :
我看了一下move是把线程无关的类变成线程相关了,并且“Bradley T. Hughes 给出说明是: QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中。”这个正是我想要的效果。
但如果这样,UI层很多参数需要穿过QThread传到OPERATION,我觉得很不爽,QThread做了个二传手。还有在更新数据时必须在OPERATION里emit信号,又是穿过QThread传到UI。数据分层做的很不理想。但其他好像没有办法解决。不知道有没有什么好建议。
注:OPERATION里emit信号是因为OPERATION中的功能需要循环依次得出一些结果,我想把这些结果一个一个地往UI显示,所以只能放到循环内了。本来OPERATION里比较纯的业务逻辑,如此就参入了表现层的东西。如果能把这个放到QThread代理层,可能会更理想些,我有些完美主义[表情]  

呵呵,
我咋总觉得你在狡辩呢?

我只是说你可以请OPERATION直接move到线程。

重新考虑一下,你原打算选择的什么?子类化QThread!怎么子类化,还不是将要在线程中进行的操作放入 run 或由run直接调用的函数中??

前提是什么?你知道哪些操作要放入线程!这些操作怎么办?还不是要从主线程(即你的OPERATION)中剥离出来??

现在怎么样了?你可以直接将要放入线程的操作从OPERATION中剥离出来,放入一个QObject中,比如叫ThreadOPERATION。然后OPERATION和ThreadOPERATION通过事件(events)或信号槽(signal&slot)通讯。

如果你想多线程,就将ThreadOPERATION移动到一个线程,如果不想多线程,就不move,这也没有任何影响。你不觉得这远比你一开始所想完美??
离线kamatyo

只看该作者 9楼 发表于: 2011-08-30
回 8楼(dbzhang800) 的帖子
我的意思是你给我的方案比我的要好,我想更加好。

然后我想把emit的操作放到ThreadOPERATION中,而不是OPERATION中,但需求似乎不允许这样。其实我的目的就是把啰嗦的事情都放到ThreadOPERATION,OPERATION是纯的业务,同时也不想把业务放到ThreadOPERATION。于是我想让OPERATION执行一个函数,告诉ThreadOPERATION需要如何与UI通信。这样如果以后事件信号这块有变动,我就不需要去改OPERATION。可能跟MVC有些类似,我不愿意M和V有任何瓜葛。

你说的很对,其实我之前的想法也面临这个问题的。

非常感谢你给我的解答,我再实际试一下,我是初学,有言辞不当请见谅。

离线kamatyo

只看该作者 10楼 发表于: 2011-09-01
回 8楼(dbzhang800) 的帖子
今天把部分程序重写了一下,加入了多线程,不过还是通过新建一个thread类实现的,用qoblect把线程move进去程序报错,一下子找不到原因,就放弃了。

不过最后还是移了部分业务操作代码到thread,里面套了个循环,依次调用业务类,这样通过thread类的某个布尔量控制循环中途退出,emit事件也都在thread里,业务类完全没有涉及UI相关的东西。

效果还行,接下来准备开多个线程跑业务,就是得考虑一下共享数据处理的问题。
快速回复
限100 字节
 
上一个 下一个