查看完整版本: [-- Qt的多线程是不是不能使用QTimer --]

QTCN开发网 -> Qt基础编程 -> Qt的多线程是不是不能使用QTimer [打印本页] 登录 -> 注册 -> 回复主题 -> 发表主题

wcrqpdb 2019-11-06 19:32

Qt的多线程是不是不能使用QTimer

会报这个  QObject::startTimer: Timers cannot be started from another thread

沉默小ai 2019-11-06 23:02
可以使用,这个提示是你跨线程操作QTimer了 这个是不允许的

wcrqpdb 2019-11-07 01:49
但这个QTimer我是在继承QThread这个类里创建的吖,在.h声明.cpp构造函数里创建

uidab 2019-11-07 08:03
wcrqpdb:但这个QTimer我是在继承QThread这个类里创建的吖,在.h声明.cpp构造函数里创建 (2019-11-07 01:49)

那就不对了,继承QThread只有在run中是另外一个线程,其他定义都属于主线程。

看看movetothread吧

wcrqpdb 2019-11-07 11:03
我见网上教程说有2种方法创建,第一种用一个类继承QThread,然后重新改写虚函数run()。当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程。第二种方法是继承一个QObject类,然后利用moveToThread()函数开启一个线程槽函数,将要花费大量时间计算的代码放入该线程槽函数中。我是用第一种的,你说用movetothread那是第二中的。那用第一种方法要怎么用QTimer
网上教程https://blog.csdn.net/naibozhuan3744/article/details/81174681


沉默小ai 2019-11-07 11:23
你实在是想用继承QThread的方式的话,把QTimer 的对象在run函数内创建,这样这个QTimer就属于这个线程了,继承的Qthread的类的创建、构造函数的实际上还是由 创建 继承的Qthread的类 的线程操作的。

wcrqpdb 2019-11-07 11:32
沉默小ai:你实在是想用继承QThread的方式的话,把QTimer 的对象在run函数内创建,这样这个QTimer就属于这个线程了,继承的Qthread的类的创建、构造函数的实际上还是由 创建 继承的Qthread的类 的线程操作的。[表情] [表情] [表情]  (2019-11-07 11:23) 

在run内创建也不行,报QObject: Cannot create children for a parent that is in a different thread.
(Parent is readWriteThread(0x21080b80), parent's thread is QThread(0x20fd2530), current thread is readWriteThread(0x21080b80)


angelus 2019-11-07 11:39
wcrqpdb:在run内创建也不行,报QObject: Cannot create children for a parent that is in a different thread.
(Parent is readWriteThread(0x21080b80), parent's thread is QThread(0x20fd2530), current thread is readWriteThread(0x21080b80)
 (2019-11-07 11:32) 

这个报错应该和qtimer无关,QTimer是可以直接实例化在run函数内,不过建议把QTimer包含进一个类中,所有run 中运行的逻辑都在这个类中实现,这样,run函数会很干净,多线程操作也会很有条理性

圣域天子 2019-11-07 11:48
Qt大量控件都存在这个跨线程问题,只能在单个线程中使用。

uidab 2019-11-07 13:57
angelus:这个报错应该和qtimer无关,QTimer是可以直接实例化在run函数内,不过建议把QTimer包含进一个类中,所有run 中运行的逻辑都在这个类中实现,这样,run函数会很干净,多线程操作也会很有条理性 (2019-11-07 11:39) 


uidab 2019-11-07 13:59
wcrqpdb:在run内创建也不行,报QObject: Cannot create children for a parent that is in a different thread.
(Parent is readWriteThread(0x21080b80), parent's thread is QThread(0x20fd2530), current thread is readWriteThread(0x21080b80)
 (2019-11-07 11:32) 

没代码不好评论,记住这种方式只有在run()中的才是另一个线程。所以你的QTimer变量也只能在这里实例化。很多人是在继承QThread的类定义了QTimer的成员变量,以为这个也是在另一个线程,其实不是。

wcrqpdb 2019-11-07 15:02
zi.h
[attachment=21036]
zu.h
[attachment=21037]
main
[attachment=21038]
zi.cpp
[attachment=21039]
zu.cpp
[attachment=21040]
QObject: Cannot create children for a parent that is in a different thread.
(Parent is zi(0x7cf9c0), parent's thread is QThread(0x176f60), current thread is zi(0x7cf9c0)
原程序[attachment=21041]

圣域天子 2019-11-07 16:35
QTimer 在线程中不要用 new
QTimer k; 就可以了。run结束后它自动释放。

不过 k 如果关联信号的话,应该依旧会存在。

你的需求的实现方式应该调整一下,在线程中使用 QTimer 发时间信号,应该是没意义了。


wcrqpdb 2019-11-07 18:02
圣域天子:QTimer 在线程中不要用 new
QTimer k; 就可以了。run结束后它自动释放。
不过 k 如果关联信号的话,应该依旧会存在。
....... (2019-11-07 16:35) 

我要定时处理数据

dbzhang800 2019-11-07 19:00
wcrqpdb:zi.h
[图片]
zu.h
[图片]
main
....... (2019-11-07 15:02) 

你在run()内写下列代码,错了。run()函数内是次线程,但是this不在次线程内,不能作为父对象。
new QTimer(this)

另外,run() 内没有 exec()函数,只把timer创建放到run内也没有意义,你代码中的槽函数又不在你的run内执行

wcrqpdb 2019-11-07 19:38
dbzhang800:你在run()内写下列代码,错了。run()函数内是次线程,但是this不在次线程内,不能作为父对象。
new QTimer(this)
另外,run() 内没有 exec()函数,只把timer创建放到run内也没有意义,你代码中的槽函数又不在你的run内执行 (2019-11-07 19:00)

要怎么写,麻烦写一下,上面有原程序

angelus 2019-11-08 09:15
wcrqpdb:要怎么写,麻烦写一下,上面有原程序
 (2019-11-07 19:38) 

写个独立的处理类,然后在里边按平时的习惯定义qtimer,和处理任务,然后把这个类实例化到run函数内,开启线程循环,至于主线程和次线程通讯,直接信号和thread中的连接上就行,这种信号通知属于跨线程信号槽,异步操作

wcrqpdb 2019-11-09 16:26
angelus:写个独立的处理类,然后在里边按平时的习惯定义qtimer,和处理任务,然后把这个类实例化到run函数内,开启线程循环,至于主线程和次线程通讯,直接信号和thread中的连接上就行,这种信号通知属于跨线程信号槽,异步操作 (2019-11-08 09:15) 

按照你的方法还是报 QObject::startTimer: Timers cannot be started from another thread

clickto 2019-11-09 23:53
在run的while里sleep啊,达到timer的效果

yanwuyue 2019-11-11 09:42
继承的不要带this,直接qtimer(),并且实例化的k也只能在run里面使用或者信号控制

巫添良 2019-11-11 22:49
    up_timer = new QTimer;
    up_timer->setInterval(1000);
    up_timer->start();
    up_timer->moveToThread(&up_img_Thread);//定时器移到子线程中
    connect(up_timer, SIGNAL(timeout()), this, SLOT(up_model_file()), Qt::DirectConnection);
    connect(this, SIGNAL(stop_up_timer()), up_timer, SLOT(stop()));
    connect(this,SIGNAL(start_up_timer()),up_timer,SLOT(start()));
    up_img_Thread.start();
这样写 定时器的槽函数就是在子线程中执行的


dbzhang800 2019-11-12 17:43
巫添良:    up_timer = new QTimer;
    up_timer->setInterval(1000);
    up_timer->start();
    up_timer->moveToThread(&up_img_Thread);//定时器移到子线程中
   &n .. (2019-11-11 22:49) 

多线程环境使用使用 Qt::DirectConnection ,通常暗示着存在设计问题

xiaohuyang 2019-11-14 10:17
dbzhang800:多线程环境使用使用 Qt::DirectConnection ,通常暗示着存在设计问题 (2019-11-12 17:43) 

使用默认的Qt::AutoConnection

angelus 2019-11-15 11:34
写了一个简单的例子,你看下,不懂可以直接问我

[attachment=21074]

圣域天子 2019-11-15 13:06
dbzhang800:多线程环境使用使用 Qt::DirectConnection ,通常暗示着存在设计问题 (2019-11-12 17:43) 

我的共享库,大多都是默认 Qt::DirectConnection 的

angelus 2019-11-15 14:11
圣域天子:我的共享库,大多都是默认 Qt::DirectConnection 的
[表情] (2019-11-15 13:06) 

主线程内直接走的是回调函数类型,异步信号走的都是事件队列,保持默认应该是最好的选择,让Qt根据实际环境去设置方式

圣域天子 2019-11-15 17:10
angelus:主线程内直接走的是回调函数类型,异步信号走的都是事件队列,保持默认应该是最好的选择,让Qt根据实际环境去设置方式
 (2019-11-15 14:11) 

这也是为什么Qt的类默认无法跨线程。
我大多要求能跨线程使用,所以一般不用默认的调用方式

angelus 2019-11-15 17:17
圣域天子:这也是为什么Qt的类默认无法跨线程。
我大多要求能跨线程使用,所以一般不用默认的调用方式 (2019-11-15 17:10)

我有点糊涂,你要求跨线程,不是应该用 Qt::QueuedConnection 吗?
Qt::DirectConnection只能在当前线程中执行。

Qt: AutoConnection
如果接收方位于发出信号的线程中,则使用Qt::DirectConnection。否则,使用Qt::QueuedConnection。
用默认的不更好吗?自动判断接收方是否跨线程


圣域天子 2019-11-15 18:00
angelus:我有点糊涂,你要求跨线程,不是应该用 Qt::QueuedConnection 吗?
Qt::DirectConnection只能在当前线程中执行。
Qt: AutoConnection
....... (2019-11-15 17:17) 

是的,但 Qt::DirectConnection 相当于与线程无关。可以在当线程程中调用其它方法。这是亲测出来的。
但 Qt::QueuedConnection 还是线程相关的。跨线程时会出问题。

dbzhang800 2019-11-16 22:08
看Qt手册的话,很少有函数标称是 threadsafe 的,但 postEvent() 是线程安全的:

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
....
Note: This function is thread-safe

这一函数,方便了我们在多线程之间传递数据(通过事件队列),而不需要手动加锁。

QueuedConnection信号槽 其实也是通过这一个函数的将 信号封装成一个对象,进而传递到目标线程的事件队列的。目标线程的事件循环发现收到对象后,将其作为函数和函数参数进行调用。

不用这一机制,也没什么错,无非Qt不保证线程安全,和常规多线程一样,自己手动加锁就好了。

wcrqpdb 2019-11-18 10:07
yanwuyue:继承的不要带this,直接qtimer(),并且实例化的k也只能在run里面使用或者信号控制 (2019-11-11 09:42) 

你可以试一下,没有this也一样不行

圣域天子 2019-11-18 12:11
dbzhang800:看Qt手册的话,很少有函数标称是 threadsafe 的,但 postEvent() 是线程安全的:
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
....
Note: This function is thread-safe
....... (2019-11-16 22:08) 

它有些处理,还是排队进行的,内部并不是业务层面的多线程。
可能是因为Qt主要是界面库,而界面处理一般都是只在主线程中,所以引起了很多线程之间不能乱跨的限制。
所以多线程还是自己控制会比较好。

rpdhunter 2019-11-20 12:10
这个明显是线程理解不到位导致的

继承QThread,重新实现run的方法其实很不好,初学者会被搞乱的,实际继承类的构造函数和槽函数(被外部对象调用时),都是运行在主线程的,只有run方法和run方法直接调用的函数是运行在子线程中的,这中间如果涉及到不能重入的或者线程不安全的对象,那么就会出现各种奇奇怪怪的错误。而且run中使用类成员,也要注意线程同步(使用Qmutex之类的同步工具),初学者根本掌握不好这些。
反而继承QObject类,然后利用moveToThread()方法创建线程更容易,这种方法不需要线程同步,所有和外部的数据传送全用信号槽就好了,所有的方法都会运行在子线程中(除了构造函数,构造函数为空就好了),更符合初学者的"常识"

fsu0413 2019-12-04 07:50
反正记住,QThread类的对象本身不在这个对象表示的线程中就完事了
而且至少要看懂最基本的英文错误描述吧。。。。。

ragtime 2019-12-27 16:01
不要用timer。用timerevent,用信号槽 这么绑定
connect(this,&MYCLASS::signalStarttimer,this,&MYCLASS::slotStartTimer);
俗称的我绑我自己。稳稳的。


查看完整版本: [-- Qt的多线程是不是不能使用QTimer --] [-- top --]



Powered by phpwind v8.7 Code ©2003-2011 phpwind
Gzip disabled