http://blog.chinaunix.net/uid-10225517-id-2968407.html
http://doc.trolltech.com/4.7/threads-qobject.html
http://wenku.baidu.com/view/b8ca6ded0975f46527d3e165.html
qt中关于线程和对象的一段描述,非常重要。
qobject特性
1. 可以被用于多个线程;
2. 可以出发信号,由其他线程来处理
3. 可以发送事件给其他线程中的对象
上述3点都基于任何一个thread都需要有自己的event loop; (其实如果了解了com的套件模型来理解这些假设以及qt的实现你会认为很自然)
也就是说不满足上述3点时候就是not threadsafe。
qobject 和它的所有subclass 都非线程安全,我们看看几种情况
1. qtobject 随时可能处于它被创建所在线程的event loop 调用中,因此你必须明白如果你想从另外一个线程访问这个对象是有风险的。
2. qtthread对象很特别,因为它被创建于的线程和它的run函数运行的线程实际上不是同一个线程。
通过上面的描述,在使用qt时候,必须非常关注对象的线程属性。
个人感觉,qt的线程属性+event loop非常像com的STA模型。 但是由于qt又允许你跨越线程直接使用对象,因此可以理解为一个非强制的sta模型,或者一个不安全你的mta。
qtojbect 以及其nonui的派生子类(
such as QTimer, QTcpSocket,QUdpSocket, QFtp, and QProcess, )都支持重入,这使得它们有可能能够在多线程环境下工作,但是有3点条件需要满足
1. qobject的子对象必须在他的父对象的线程上创建
2. 在删除qthread之前需要将所有在这个thread上创建的对象删除,比如建议用stack对象在run上。
3. qobject对象需要在创建它的线程中被删除,如果不能满足建议使用deltelater。 但是后者也需要这个对象所在的创建线程用用eventloop。
4. 非常重要qtwidet这些ui类的子对象,仅限于适用于ui线程。 这个要求模型上ui对象存在于uithread,workerthread仅仅执行计算;如果计算的结果需要通知ui对象,可以通过signal。
事件和对象
1. 事件发给某个对象,表示将事件投递到这个事件处理对象所在的线程event loop。
2. qobject 如果创建早于qtapplication那么将导致主线程的事件循环仅仅能够处理那些已经投递的事件(qtapplication创建前),之后投递的事件,将由于这些对象的thread属性为空而无法处理;当然也可以为这些对象调用movetothread。
3. 事件监视对象的设置要求其必须存在于被监视对象的同一个线程内。
4. sendevent 要求事件处理对象和调用sendevent两者处于同一个线程。 这个可以简单理解为qt貌似没有提供
slot、signal 跨线程使用
qt支持的槽-信号模型有如下几种:
1. 自动连接模型(默认),将自动根据触发者和处理者来选择使用directconnection 或者queuedconnection
2. 直接连接,两者处于同一个线程
3. queued连接,处于不同线程,且接受者线程有eventloop
4. 阻塞型queued,处于不同线程,触发者需要等待called slot 返回;注意如果在同一个线程中使用这个标记可能会deadlock.
5. 唯一连接,基本同auto,只是它不会执行重复连接。
通过上面的描述,可以看到基于qt已经提供了rvmin中msgbus的几乎所有功能,包括qt本身提供的对象回收。
qt中有两个概念,thread-safe 和重入reentrancy
1. thread-safe 的含义是,函数可以被多个线程同时呼叫,因为函数使用的共享对象被保护了,或者说序列化了。
2. reentrancy 的含义是,函数可以被多个线程同时呼叫,但是每个呼叫环境中数据只能有一份,并不能共享。
因此从这个概念来说,很多c++ 类都是可重入的,但是不一定是线程安全的。
简单来说前者表示对象或者函数的成员有保护; 或者表示函数或者对象只使用自有成员比如tls 或者 local。