Qt 是一种基于 C++ 的跨平台 GUI 系统,能够提供给用户
构造图形用户界面的强
大功能。为了满足用户
构造复杂图形界面系统
的需求,Qt 提供了丰富的多线程编
程支持。Qt 主要从三个方面对多线
程编程提供支持:一、
构造了一些基本的与平
台无关的线程类;二、
提交用户自定义事件的
Thread-saf
e 方式;三、多种线程间
同步机制,如信号量,
全局锁。本文着重讨论
Qt 中的多线程类及其多线
程通信方法,同时介绍
了QT在Linux和
WINDOWS平台下
多线程程序的编译方法
。
关键词:QT,QTE ,多线程通信,QT编
译,linux,wi
ndows
一、 QT的线程类
在 Qt 系统中与线程相关的最 重要的类是 QThread 类,该类提供了创建一
个新线程以及控制线程
运行的各种方法。线程
是通过 QThread::r
un() 重载函数开始执行的。
为编写出支持多线程的 程序,还需要实现两个
不同的线程对共有数据
的互斥访问,因此 Qt 还提供了 QMutex 类,一个线程在访问临
界数据时,需要加锁,
此时其他线程是无法对
该临界数据同时加锁的
,直到前一个线程释放
该临界数据。通过这种
方式才能实现对临界数
据的原子操作。
二、 QT的线程间通 信
在 Qt 系统中,运行着一个G UI 主事件线程,这个主线
程从窗口系统中获取事
件,并将它们分发到各
个组件去处理。在 QThread 类中有一种从非主事件
线程中将事件提交给一
个对象的方法,也就是
QThread::p
ostEvent()
方法,该方法提供了Q
t 中的一种 Thread-saf
e 的事件提交过程。提交
的事件被放进一个队列
中,然后 GUI 主事件线程被唤醒并将
此事件发给相应的对象
,这个过程与一般的窗
口系统事件处理过程是
一样的。当事件处理过
程被调用时,是在主事
件线程中被调用的,而
不是在调用QThre
ad::postEv
ent 方法的线程中被调用。
1.、系统定义的事件 的提交
在 Qt 系统中,定义了很多种 类的事件,如定时器事
件、鼠标移动事件、键
盘事件、窗口控件事件
等。通常,事件都来自
底层的窗口系统。Qt
的主事件循环函数从系
统的事件队列中获取这
些事件,并将它们转换
为 QEvent,然后传
给相应的 QObjects 对象。
如下所示:
QWidget *mywidget;
void MyThread:: run()
{
QThread::p ostEvent(M
yWidget, new QPaintEven
t(QRect(0,
0,100,100)
));
}
在MyThread线 程中发送重画事件给M
yWidget窗体类
。
MyWidget的p aintEvent事
件响应会被自动调用,
用以响应MyThre
ad发送过来的重画事
件。
void MyWidget:: paintEvent
(QPaintEve
nt*)
{
}
关键词:QT,QTE
一、 QT的线程类
在 Qt 系统中与线程相关的最
为编写出支持多线程的
二、 QT的线程间通
在 Qt 系统中,运行着一个G
1.、系统定义的事件
在 Qt 系统中,定义了很多种
如下所示:
QWidget *mywidget;
void MyThread::
{
QThread::p
}
在MyThread线
MyWidget的p
void MyWidget::
{
}
2.、自定义事件
的提交
为了满足用户的需 求,Qt 系统还提供了一个 QCustomEve
nt 类,用于用户自定义事
件,这些自定义事件可
以利用 QThread::p
ostEvent()
或者QApplica
tion::post
Event() 被发给各种控件或其他
QObject 实例,而 QWidget 类的子类可以通过 QWidget::c
ustomEvent
() 事件处理函数方便地接
收到这些自定义的事件
。需要注意的是:QC
ustomEvent
对象在创建时都带有一
个类型标识 id 以定义事件类型,为了
避免与 Qt 系统定义的事件类型冲
突,该 id 值应该大于枚举类型 QEvent::Ty
pe 中给出的 "User" 值。
如下所示:
UserEven t类是用户自定义的事
件类,其事件标识为3
46798,显然不会
与系统定义的事件类型
冲突。
class UserEvent : public QCustomEve nt //用户自定义的事件
类
{
public:
UserEven t(QString s) : QCustomEve
nt(346798)
, sz(s) { ; }
QString str() const { return sz; }
private:
QString sz;
};
UserThre ad类是由QThre
ad类继承而来的子类
,在该类中除了定义有
关的变量和线程控制函
数外,最主要的是定义
线程的启动函数Use
rThread::r
un(),在该函数中
创建了一个用户自定义
事件UserEven
t,并利用QThre
ad类的postEv
ent函数提交该事件
给相应的接收对象。
class UserThread : public QThread
//用户定义的线程类
{
public:
UserThre ad(QObject
*r, QMutex *m, QWaitCondi
tion *c);
QObject *receiver;
}
void UserThread ::run() //线程类启动函数,
在该函数中创建了一个
用户自定义事件
{UserEve nt *re = new UserEvent(
resultstri
ng);
QThread ::postEven
t(receiver
, re);
}
UserWidg et类是用户定义的用
于接收自定义事件的Q
Widget类的子类
,该类利用slotG
o()函数创建了一个
新的线程recv(U
serThread类
),当收到相应的自定
义事件(即id为34
6798)时,利用c
ustomEvent
函数对事件进行处理。
void UserWidget ::slotGo()
//用户定义控件
的成员函数
{mutex.l ock();
if (! recv)
recv = new UserThread (this, &mutex, &condition
);
recv->st art();
mutex.un lock();
}
void UserWidget ::customEv
ent(QCusto
mEvent *e) //用户自定义事件处
理函数
{if (e->type() ==346798)
{
UserEven t *re = (UserEvent
*) e;
news tring = re->str();
}
}
在这个例子中,U serWidget对
象中创建了新的线程U
serThread,
用户可以利用这个线程
实现一些周期性的处理
(如接收底层发来的消
息等),一旦满足特定
条件就提交一个用户自
定义的事件,当Use
rWidget对象收
到该事件时,可以按需
求做出相应的处理,而
一般情况下,User
Widget对象可以
正常地执行某些例行处
理,而完全不受底层消
息的影响。
三、 QT多线程程序 的编译
先决条件:有编译成功 的多线程库 如libqt-mt.
so(QT库)或 libqte-mt.
so(QTE库)
WINDOWS下:在 qconfig.h 文件中增加一个选项来
定义宏 QT_THREAD_
SUPPORT
Linux下:在ma kefile中的链接
选项中加入多线程库-
lqt-mt或-lq
te-mt,在编译选
项中增加-DQT_T
HREAD_SUPP
ORT 来增加线程支持宏 QT_THREAD_
SUPPORT。
为了满足用户的需
如下所示:
UserEven
class UserEvent : public QCustomEve
{
public:
UserEven
QString str() const { return sz; }
private:
QString sz;
};
UserThre
class UserThread
{
public:
UserThre
QObject *receiver;
}
void UserThread
{UserEve
QThread
}
UserWidg
void UserWidget
{mutex.l
if (! recv)
recv = new UserThread
recv->st
mutex.un
}
void UserWidget
{if (e->type()
{
UserEven
news
}
}
在这个例子中,U
三、 QT多线程程序
先决条件:有编译成功
WINDOWS下:在
Linux下:在ma
本文来自互联网!