基于 Qt QThread 的同步任务队列和异步任务队列

本文介绍了如何使用 Qt QThread 构建同步和异步任务队列,包括串行任务队列、并发网络请求任务队列,并探讨了QThreadPool和QRunnable的局限性。重点讨论了线程间的同步、任务调度和异步任务的完成通知机制。

Qt QTread 背景知识

1、moveToThread
QObject worker;
worker.moveToThread(_thread);

这个 worker 不能指定parent,否则 moveToThread 会失败。

同样,如果 worker moveToThread 后,不能设置非同一线程下的 parent。
即,对象树下的所有对象、都必须在同一线程里,否则无论是修改对象树、还是修改线程,都会失败。

2、QThread 对象释放掉,但线程未必停止了。正确的停止方式:
  首先请求中断任务,QThread 在 run时,可能会存有多个待执行的任务,用 while 循环来一个个执行的
因此,QThread 对象释放时,先请求中断 requestInterruption,run 中的 while 则判断是否有中断

while(!isInterruptionRequested()) 
    requestInterruption();
    // 然后 发出 quit event
    quit();
    // 等待退出 QThread 的 event loop
    wait();
}

3、实例分析
  telegram 的 taskqueue, 对 task 的执行、包括结束,都是在同一个 worker 工作函数里执行的。
  主线程生成 task,加入到 taskqueue,taskqueue 通过信号 taskadded,通知 worker 开始执行任务, worker 从 task 队列取出 task,调用 task->process(),完成后,发出 worker 的 taskFinished 信号,不在同一线程、所以 生成 event 插入到 主线程的 event loop 里,然后主动调用 QCoreApplication::processEvents(),这时候 worker 的 taskFinished 信号会被处理掉,即,一个任务 process 后,立刻 finished。
   telegram worker的本意是,主线程添加 task 至 taskqueue ,将 task 加入到 task 列表、然后发出 taskadded 信号就结束了,work 的工作函数会被 taskadded 信号唤醒,工作函数 while 检查线程是否中断,否则从 task 列表里取出一个 task、然后 process、发出 finished 信号,再次检查线程是否中断。
  这里的问题是,主线程可能在上个 task 还在执行的时候,如果再添加一个 task 进来、会塞 taskadded 事件到 event loop 里,那么上一个 work 工作函数在 task finish 之后、调用 QCoreApplication::processEvents() 的时候,会有两个 work 工作函数被执行,虽然 加了锁,不会循环执行相同的任务,但其实已经跑飞了。

 
 
 

一个 串行 的任务队列:

利用 QThread run 的 event loop,来实现任务调度。

Created with Raphaël 2.1.2 开始 传入待执行任务 将待执行的任务放进 FIFO 队列里 检查启动线程 发出执行任务信号
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值