真实版离婚证在线生成:Linux程序开发:QT中的多线程编程
来源:百度文库 编辑:偶看新闻 时间:2024/04/28 19:40:36
Linux程序开发:QT中的多线程编程
在下面的例子中,显示了多线程编程中如何利用用户自定义事件类。UserEvent类是用户自定义的事件类,其事件标识为346798,显然不会与系统定义的事件类型冲突。class UserEvent : public QCustomEvent //用户自定义的事件类 { public: UserEvent(QString s) : QCustomEvent(346798), sz(s) { ; } QString str() const { return sz; } private: QString sz; };
UserThread类是由QThread类继承而来的子类,在该类中除了定义有关的变量和线程控制函数外,最主要的是定义线程的启动函数UserThread::run(),在该函数中创建了一个用户自定义事件UserEvent,并利用QThread类的postEvent函数提交该事件给相应的接收对象。
class UserThread : public QThread //用户定义的线程类 { public: UserThread(QObject *r, QMutex *m, QWaitCondition *c); QObject *receiver; } void UserThread::run() //线程类启动函数,在该函数中创建了一个用户自定义事件 {UserEvent *re = new UserEvent(resultstring); QThread::postEvent(receiver, re); }
UserWidget类是用户定义的用于接收自定义事件的QWidget类的子类,该类利用slotGo()函数创建了一个新的线程recv(UserThread类),当收到相应的自定义事件(即id为346798)时,利用customEvent函数对事件进行处理。
void UserWidget::slotGo() //用户定义控件的成员函数 { mutex.lock(); if (! recv) recv = new UserThread(this, &mutex, &condition); recv->start(); mutex.unlock(); } void UserWidget::customEvent(QCustomEvent *e) //用户自定义事件处理函数 { if (e->type()==346798) { UserEvent *re = (UserEvent *) e; newstring = re->str(); } }
在这个例子中,UserWidget对象中创建了新的线程UserThread,用户可以利用这个线程实现一些周期性的处理(如接收底层发来的消息等),一旦满足特定条件就提交一个用户自定义的事件,当UserWidget对象收到该事件时,可以按需求做出相应的处理,而一般情况下,UserWidget对象可以正常地执行某些例行处理,而完全不受底层消息的影响。
4、利用定时器机制实现多线程编程
为了避免Qt系统中多线程编程带来的问题,还可以使用系统中提供的定时器机制来实现类似的功能。定时器机制将并发的事件串行化,简化了对并发事件的处理,从而避免了thread-safe方面问题的出现。
在下面的例子中,同时有若干个对象需要接收底层发来的消息(可以通过Socket、FIFO等进程间通信机制),而消息是随机收到的,需要有一个GUI主线程专门负责接收消息。当收到消息时主线程初始化相应对象使之开始处理,同时返回,这样主线程就可以始终更新界面显示并接收外界发来的消息,达到同时对多个对象的控制;另一方面,各个对象在处理完消息后需要通知GUI主线程。对于这个问题,可以利用第3节中的用户自定义事件的方法,在主线程中安装一个事件过滤器,来捕捉从各个对象中发来的自定义事件,然后发出信号调用主线程中的一个槽函数。
另外,也可以利用Qt中的定时器机制实现类似的功能,而又不必担心Thread-safe问题。下面就是有关的代码部分:
在用户定义的Server类中创建和启动了定时器,并利用connect函数将定时器超时与读取设备文件数据相关联:
Server:: Server(QWidget *parent) : QWidget(parent) { readTimer = new QTimer(this); //创建并启动定时器 connect(readTimer, SIGNAL(timeout()),this, SLOT(slotReadFile())); //每当定时器超时时调用函数slotReadFile读取文件 readTimer->start(100); } slotReadFile函数负责在定时器超时时,从文件中读取数据,然后重新启动定时器: int Server::slotReadFile() // 消息读取和处理函数 { readTimer->stop(); //暂时停止定时器计时 ret = read(file, buf ); //读取文件 if(ret == NULL) { readTimer->start(100); //当没有新消息时,重新启动定时器 return(-1); } else 根据buf中的内容将消息分发给各个相应的对象处理……; readTimer->start(100); //重新启动定时器 }
在该程序中,利用了类似轮循的方式定时对用户指定的设备文件进行读取,根据读到的数据内容将信息发送到各个相应的对象。用户可以在自己的GUI主线程中创建一个Server类,帮助实现底层的消息接收过程,而本身仍然可以处理诸如界面显示的问题。当各个对象完成处理后,通过重新启动定时器继续进行周期性读取底层设备文件的过程。当然,这种方法适合于各对象对事件的处理时间较短,而底层设备发来消息的频率又相对较慢的情况。