• 7721阅读
  • 34回复

[提问]Qt的多线程是不是不能使用QTimer [复制链接]

上一主题 下一主题
离线wcrqpdb
 

只看楼主 倒序阅读 楼主  发表于: 2019-11-06
会报这个  QObject::startTimer: Timers cannot be started from another thread
离线沉默小ai

只看该作者 1楼 发表于: 2019-11-06
可以使用,这个提示是你跨线程操作QTimer了 这个是不允许的
离线wcrqpdb

只看该作者 2楼 发表于: 2019-11-07
但这个QTimer我是在继承QThread这个类里创建的吖,在.h声明.cpp构造函数里创建
离线uidab

只看该作者 3楼 发表于: 2019-11-07
回 wcrqpdb 的帖子
wcrqpdb:但这个QTimer我是在继承QThread这个类里创建的吖,在.h声明.cpp构造函数里创建 (2019-11-07 01:49)

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

看看movetothread吧
有时候为了工作直接获得答案,而我却失去了思考的乐趣!


飘啊飘,何时能安居!
离线wcrqpdb

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

离线沉默小ai

只看该作者 5楼 发表于: 2019-11-07
你实在是想用继承QThread的方式的话,把QTimer 的对象在run函数内创建,这样这个QTimer就属于这个线程了,继承的Qthread的类的创建、构造函数的实际上还是由 创建 继承的Qthread的类 的线程操作的。
离线wcrqpdb

只看该作者 6楼 发表于: 2019-11-07
回 沉默小ai 的帖子
沉默小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

只看该作者 7楼 发表于: 2019-11-07
回 wcrqpdb 的帖子
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函数会很干净,多线程操作也会很有条理性
在线圣域天子

只看该作者 8楼 发表于: 2019-11-07
Qt大量控件都存在这个跨线程问题,只能在单个线程中使用。
离线uidab

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

有时候为了工作直接获得答案,而我却失去了思考的乐趣!


飘啊飘,何时能安居!
离线uidab

只看该作者 10楼 发表于: 2019-11-07
回 wcrqpdb 的帖子
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

只看该作者 11楼 发表于: 2019-11-07
zi.h

zu.h

main

zi.cpp

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)
原程序 a1.rar (5 K) 下载次数:2
在线圣域天子

只看该作者 12楼 发表于: 2019-11-07
QTimer 在线程中不要用 new
QTimer k; 就可以了。run结束后它自动释放。

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

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

离线wcrqpdb

只看该作者 13楼 发表于: 2019-11-07
回 圣域天子 的帖子
圣域天子:QTimer 在线程中不要用 new
QTimer k; 就可以了。run结束后它自动释放。
不过 k 如果关联信号的话,应该依旧会存在。
....... (2019-11-07 16:35) 

我要定时处理数据
离线dbzhang800

只看该作者 14楼 发表于: 2019-11-07
回 wcrqpdb 的帖子
wcrqpdb:zi.h
[图片]
zu.h
[图片]
main
....... (2019-11-07 15:02) 

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

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

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

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

只看该作者 16楼 发表于: 2019-11-08
回 wcrqpdb 的帖子
wcrqpdb:要怎么写,麻烦写一下,上面有原程序
 (2019-11-07 19:38) 

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

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

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

只看该作者 18楼 发表于: 2019-11-09
在run的while里sleep啊,达到timer的效果
离线yanwuyue

只看该作者 19楼 发表于: 2019-11-11
继承的不要带this,直接qtimer(),并且实例化的k也只能在run里面使用或者信号控制
离线巫添良

只看该作者 20楼 发表于: 2019-11-11
    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

只看该作者 21楼 发表于: 2019-11-12
回 巫添良 的帖子
巫添良:    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

只看该作者 22楼 发表于: 2019-11-14
回 dbzhang800 的帖子
dbzhang800:多线程环境使用使用 Qt::DirectConnection ,通常暗示着存在设计问题 (2019-11-12 17:43) 

使用默认的Qt::AutoConnection
离线angelus

只看该作者 23楼 发表于: 2019-11-15
写了一个简单的例子,你看下,不懂可以直接问我

例子 threadTest.zip (4 K) 下载次数:9
在线圣域天子

只看该作者 24楼 发表于: 2019-11-15
回 dbzhang800 的帖子
dbzhang800:多线程环境使用使用 Qt::DirectConnection ,通常暗示着存在设计问题 (2019-11-12 17:43) 

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

只看该作者 25楼 发表于: 2019-11-15
回 圣域天子 的帖子
圣域天子:我的共享库,大多都是默认 Qt::DirectConnection 的
[表情] (2019-11-15 13:06) 

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

只看该作者 26楼 发表于: 2019-11-15
回 angelus 的帖子
angelus:主线程内直接走的是回调函数类型,异步信号走的都是事件队列,保持默认应该是最好的选择,让Qt根据实际环境去设置方式
 (2019-11-15 14:11) 

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

只看该作者 27楼 发表于: 2019-11-15
回 圣域天子 的帖子
圣域天子:这也是为什么Qt的类默认无法跨线程。
我大多要求能跨线程使用,所以一般不用默认的调用方式 (2019-11-15 17:10)

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

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

在线圣域天子

只看该作者 28楼 发表于: 2019-11-15
回 angelus 的帖子
angelus:我有点糊涂,你要求跨线程,不是应该用 Qt::QueuedConnection 吗?
Qt::DirectConnection只能在当前线程中执行。
Qt: AutoConnection
....... (2019-11-15 17:17) 

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

只看该作者 29楼 发表于: 2019-11-16
看Qt手册的话,很少有函数标称是 threadsafe 的,但 postEvent() 是线程安全的:

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

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

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

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

只看该作者 30楼 发表于: 2019-11-18
回 yanwuyue 的帖子
yanwuyue:继承的不要带this,直接qtimer(),并且实例化的k也只能在run里面使用或者信号控制 (2019-11-11 09:42) 

你可以试一下,没有this也一样不行
在线圣域天子

只看该作者 31楼 发表于: 2019-11-18
回 dbzhang800 的帖子
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

只看该作者 32楼 发表于: 2019-11-20
这个明显是线程理解不到位导致的

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

只看该作者 33楼 发表于: 2019-12-04
反正记住,QThread类的对象本身不在这个对象表示的线程中就完事了
而且至少要看懂最基本的英文错误描述吧。。。。。
离线ragtime

只看该作者 34楼 发表于: 2019-12-27
不要用timer。用timerevent,用信号槽 这么绑定
connect(this,&MYCLASS::signalStarttimer,this,&MYCLASS::slotStartTimer);
俗称的我绑我自己。稳稳的。
快速回复
限100 字节
 
上一个 下一个