Qt 多线程之逐线程事件循环 下篇

原文在这里:http://mobile.51cto.com/symbian-270705.htm程序员

Qt 多线程之逐线程事件循环是本文介绍的内容,是接着上篇文章继续介绍的。Qt 多线程之可重入与线程安全 上篇,请先看本篇内容。安全

每一个线程能够有它的事件循环,初始线程开始它的事件循环需使用QCoreApplication::exec(),别的线程开始它的事件循环须要用QThread::exec().像QCoreApplication同样,QThreadr提供了exit(int)函数,一个quit() slot。多线程

线程中的事件循环,使得线程可使用那些须要事件循环的非GUI 类(如,QTimer,QTcpSocket,QProcess)。也能够把任何线程的signals链接到特定线程的slots,也就是说信号-槽机制是能够跨线程使用的。对于在QApplication以前建立的对象,QObject::thread()返回0,这意味着主线程仅为这些对象处理投递事件,不会为没有所属线程的对象处理另外的事件。能够用QObject::moveToThread()来改变它和它孩子们的线程亲缘关系,假如对象有父亲,它不能移动这种关系。在另外一个线程(而不是建立它的那个线程)中delete QObject对象是不安全的。除非你能够保证在同一时刻对象不在处理事件。能够用QObject::deleteLater(),它会投递一个DeferredDelete事件,这会被对象线程的事件循环最终选取到。ide

假如没有事件循环运行,事件不会分发给对象。举例来讲,假如你在一个线程中建立了一个QTimer对象,但从没有调用过exec(),那么QTimer就不会发射它的timeout()信号.对deleteLater()也不会工做。(这一样适用于主线程)。你能够手工使用线程安全的函数QCoreApplication::postEvent(),在任什么时候候,给任何线程中的任何对象投递一个事件,事件会在那个建立了对象的线程中经过事件循环派发。事件过滤器在全部线程中也被支持,不过它限定被监视对象与监视对象生存在同一线程中。相似地,QCoreApplication::sendEvent(不是postEvent()),仅用于在调用此函数的线程中向目标对象投递事件。函数

从别的线程中访问QObject子类post

QObject和全部它的子类是非线程安全的。这包括整个的事件投递系统。须要牢记的是,当你正从别的线程中访问对象时,事件循环能够向你的QObject子类投递事件。假如你调用一个不生存在当前线程中的QObject子类的函数时,你必须用mutex来保护QObject子类的内部数据,不然会遭遇灾难或非预期结果。像其它的对象同样,QThread对象生存在建立它的那个线程中---不是当QThread::run()被调用时建立的那个线程。通常来说,在你的QThread子类中提供slots是不安全的,除非你用mutex保护了你的成员变量。性能

另外一方面,你能够安全的从QThread::run()的实现中发射信号,由于信号发射是线程安全的。优化

跨线程的信号-槽ui

Qt支持三种类型的信号-槽链接:spa

1,直接链接,当signal发射时,slot当即调用。此slot在发射signal的那个线程中被执行(不必定是接收对象生存的那个线程)

2,队列链接,当控制权回到对象属于的那个线程的事件循环时,slot被调用。此slot在接收对象生存的那个线程中被执行

3,自动链接(缺省),假如信号发射与接收者在同一个线程中,其行为如直接链接,不然,其行为如队列链接。

链接类型可能经过以向connect()传递参数来指定。注意的是,当发送者与接收者生存在不一样的线程中,而事件循环正运行于接收者的线程中,使用直接链接是不安全的。一样的道理,调用生存在不一样的线程中的对象的函数也是否是安全的。QObject::connect()自己是线程安全的。

多线程与隐含共享

Qt为它的许多值类型使用了所谓的隐含共享(implicit sharing)来优化性能。原理比较简单,共享类包含一个指向共享数据块的指针,这个数据块中包含了真正原数据与一个引用计数。把深拷贝转化为一个浅拷贝,从而提升了性能。这种机制在幕后发生做用,程序员不须要关心它。若是深刻点看,假如对象须要对数据进行修改,而引用计数大于1,那么它应该先detach()。以使得它修改不会对别的共享者产生影响,既然修改后的数据与原来的那份数据不一样了,所以不可能再共享了,因而它先执行深拷贝,把数据取回来,再在这份数据上进行修改。例如:

 
  1. void QPen::setStyle(Qt::PenStyle style)  
  2.  {  
  3.      detach();           // detach from common data  
  4.      d->stylestyle = style;   // set the style member  
  5.  }  
  6.  
  7.  void QPen::detach()  
  8.  {  
  9.      if (d->ref != 1) {  
  10.          ...             // perform a deep copy  
  11.      }  
  12.  } 

通常认为,隐含共享与多线程不太和谐,由于有引用计数的存在。对引用计数进行保护的方法之一是使用mutex,但它很慢,Qt早期版本没有提供一个满意的解决方案。从4.0开始,隐含共享类能够安全地跨线程拷贝,如同别的值类型同样。它们是彻底可重入的。隐含共享真的是"implicit"。它使用汇编语言实现了原子性引用计数操做,这比用mutex快多了。

假如你在多个线程中同进访问相同对象,你也须要用mutex来串行化访问顺序,就如同其余可重入对象那样。总的来说,隐含共享真的给”隐含“掉了,在多线程程序中,你能够把它们当作是通常的,非共享的,可重入的类型,这种作法是安全的。

小结:Qt 多线程之逐线程事件循环的内容介绍完了,但愿本篇文章能帮你解决问题,更多内容请参考编辑推荐。