转载自http://baoguanghua.blog.sohu.com/112599295.html
Qt线程基础
Qt通过与平台无关的线程类提供了对线程的支持,通过一种线程安全方式的事件传递和在线程间通过信号和槽的方式连接达到了它的目的。这使得开发多线程的Qt应用程序和发挥多处理器的优势变得容易。在不冻结应用程序的用户界面的情况下,多线程编程也是一种有效的处理费时操作的方法。
早前的Qt版本在没有线程的支持下需要提供一个编译选项以编译出这个类库。自从Qt4.0后,提供了线程库的支持。
这个文档是提供给那些对多线程编程有丰富的知识和经验的读者的。
线程相关类库
Qt包含以下线程类库:
QThread :提供了开一个新线程的方式
QThreadStorage :提供了党线程的数据存储
QMutex :提供了互斥量和互斥操作
QMutexLocker :是一个方便的类,通过它可以自动死锁和解锁一个QMutex类(实例)。
QReadWriteLock :提供了一个死锁允许同时进行读写操作
QReadLocker 和 QWriteLocker :是一组方便的类,可以自动死锁和解锁一个QReadWriteLock类。
QSemaphore :提供了一个整型信号灯(一种泛化的互斥)
QWaitCondition :提供一种方式使线程沉睡(sleep)直到被另一个线程唤醒(wake up)
QAtomicInt :提供对整型的自动操作
QAtomicPointer :提供对指针的自动操作
创建一个线程
创建一个线程,只需创建一个QThread类的子类和重载它的run()函数,如下:
class MyThread : public QThread
{
Q_OBJECT
protected:
void run();
};
void MyThread::run()
{
...
}
然后,实例化一个线程对象和调用QThread::start()。在函数run()中在中的代码将会在新建的独立线程中指行。关于创建线程解释的更多资料在QThread文档里。
注意,QCoreApplication::exec()必须一直被主线程调用(这个线程执行函数main()),而不是一个QThread类。在GUI应用程序里,主线程也被称作GUI线程,因为它是可以进行相关GUI操作的唯一线程。
另外,你必须在创建一个QThread之前创建QApplication (或者 QCoreApplication)。
理解实例化的对象所属的线程
例1:
1. class MThread :public QThread
2. {
3. public:
4. MThread();
5. ~MThread();
6. void run();
7. void foo();
8. ...
9.
10. };
1. class MDialog :public QDialog
2. {
3. ...
4. MThread *mythread;
5. };
6. MDialog::MDialog()
7. {
8. mythread = new MThread;
9. ...
10. }
需要注意的是,QThread对象的实例mythread是属于创建它的线程(线程A,即MDialog所在的线程)的,mythread的所有程序代码与数据都放在与MDialog相同的空间中.这时的mythread,就像任何普通的自己定义的类的实例一样.但是在调用mythread->start()之后,mythread的run()函数中的代码会在新的线程(线程B)中执行.在run()函数中声明的变量\实例化的对象,都属于线程B.但是mythread的所有代码,都还在存储在线程A中,只是run()函数的"执行"是在线程B中.
在MDialog中,使用
1. mythread->foo();
foo()是在线程A中执行的.
在MDialog中使用
1. connect(this, SIGNAL(sigDialogSignal()), mythread, SLOT(slotThreadSlot()));
当emit sigDialogSignal()时,是会在MDialog所在的线程A中执行的.因为mythread与MDialog同属于一个线程, 这时thread可以看做一个普通类的实例.另外,因为connect函数的连接方式默认是自动连接,而对同属于一个纯种的两个对象,自动连接会使用直接连接,即slot在发出signal的线程中立即执行.
线程A和B所含对象和运行的函数:
* 这里connect()的连接方式是直接连接方式(Qt::DirectConnection)