[转]QT多线程异步调⽤
QT多线程异步调⽤,类似MFC的PostThreadMessage
blog.csdn/dongfangyu/article/details/5930129
在MFC中,每个界⾯线程都会有⼀个消息队列,通过函数PostThreadMessage,线程之间可以互发消息,由于Post的⽅式是⾮阻塞的,因此系统可以表现出很好的性能。这种消息机制是多线程之间异步调⽤的极佳⽅式。
笔者最近学习QT4.5.3的时候,想在QT中到类似于相似的机制,但是暂时没有发现。于是想,没有就创造它。以下描述我如何使QT拥有MFC的消息机制。
MFC的消息机制,其实就是通过每个消息ID对应函数地址来实现的。明⽩了这个,构造此机制就简单了。⾸先使⽤StlPort的hash_map建⽴消息ID与回调函数地址的映射表,之所以⽤hash_map,是由于其时间复杂度很低,⽽且不会随着表项的增多⽽变慢,但会增加内存使⽤量,在现在内存较⼤的年代,这个问题不⼤。
其次,是通过QThread继续,得到⼀个基类线程,该线程假设命名MsgThd,在该线程中,配备有hash_map,同时再使⽤StlPort的vector建⽴⼀个消息队列。重载QThread的run函数,其中是⼀个循环,
该循环中不停从vector中尝试得到消息,若得到消息ID,则尝试根据此消息ID,从hash_map得到回调函数地址,若回调函数地址有效,则执⾏该函数。否则,休眠⼀定时间(⽐如1ms),然后继续从vector中尝试得到消息,周⽽复始。此时,凡是从MsgThd继续的线程已经具有消息队列了。
再次,如何使⽤该MsgThd呢?⽅法是,凡是需要消息队列的线程,需从MsgThd继续,定义消息ID,定义回调函数,然后把它们放⼊hash_map中。举例,若线程A,B都是从MsgThd继续,若线程A要给线程B发⼀个异步消息,那么只需要线程A往线程B的vector中放⼊⼀个消息即可,若你喜爱的话,这个动作的函数接⼝可以写成PostThreadMessage。当然,存放消息的vector,须⽤加锁解锁,因为它极有可能出现线程A与线程B同时访问的情况,在QT中,可以使⽤互斥量QMutex。
以上所说,是实现QT多线程异步调⽤的第⼀种⽅式。
以下所说,第⼆种⽅式。这是笔者学习QT⼏天后发现的J,因为随着对QT的熟知,接触到越来越多的内容之后,便发现QT本⾝有这样的机制。
⽽这种机制存在于函数QApplication::postEvent中,此函数相当于MFC的PostThreadMessage。⽹上有⼤量关于QT的讯息,但我还没有到对这个问题讲得较清楚的。我以下解释,不是最清楚的,但说完了,⼤家就会使⽤了。
新建⼀个类,⽐如MsgThd,继续⾃QThread,重写run函数,⾥⾯就⼀个函数exec();据说,exec()是消息机制的触发函数。重写event函数,据说,所有事件(Event)都会经过该函数,类似于MFC的PreTranslateMessage。(两个“据说”,说明说法仅供参考,笔者也是刚接触⼏天,莫怪笔者误⼈⼦弟。等我把QT源代码看完之后,就没有“据说”了,呵呵。)
假设线程A需要给线程B发消息,在线程A中有代码举例如下:
QEvent* pEvent = new QEvent((QEvent::Type)1234);
QApplication::postEvent( pThread_B, pEvent );
其中1234,是⾃⼰定义的,只要⼤于QT的保留值1024即可。就像你在MFC⾃定义消息的时候,需要⼤于WM_USER(0x0400)⼀样。
上⾯两句的意思是说,线程A产⽣了⼀个事件,它发给了线程B。
因此线程B中的event函数可能要这样写:
bool Thread_B::event(QEvent * pEvent )
{
// 截获住⾃定义的事件
if ( pEvent->type() == (QEvent::Type)1234 )
{
std::cout<<"这句话替换成你需要调⽤的函数"<<std::endl;
}
return MsgThd::event(pEvent);
}postthreadmessage
这就是第⼆种⽅式,实现QT多线程异常调⽤。
可以⾃訂事件類型,最簡單的⽅式,是透過QEvent::Type指定事件類型的常數值,在建構QCustomEvent時作為建構引數並透過postEvent()傳送事件,例如:
const QEvent::Type MyEvent = (QEvent::Type) 9393;
...
QApplication::postEvent(object, new QCustomEvent(MyEvent));
⾃訂事件必須定義事件號碼(Event number),⾃定義的事件號碼必須⼤於QEvent::Type的列舉值,通常1024以下的值是保留給Qt預先定義的事件類型來使⽤。
object是事件的接受者,使⽤ postEvent()⽅法時,事件必須以new的⽅式建⽴,在事件處理完畢之後,會⾃動將事件delete,postEvent()會將事件放⾄事件佇列的尾端,然後⽴即返回。若要強迫Qt⾺上處理先前postEvent()排到佇列的事件,則可以使⽤sendPostedEvents()。
您可以使⽤sendEvent()⽅法,事件會⽴即送⾄接受者,sendEvent()⽅法的事件不會被delete,所以通常建⽴在堆疊(Stack)區,例如:
CustomEvent event("Event Message");
QApplication::sendEvent(object, &event);
⾃訂的事件類型必須是QEvent的⼦類別,通常繼承QCustomEvent類別,建⽴⾃訂事件類別可以獲得更多的型態安全(Type safety)。
要處理⾃訂事件,可以重新定義customEvent()⽅法,例如:
void CustomWidget::customEvent(QCustomEvent *event) {
CustomEvent *customEvent = static_cast<CustomEvent *>(event);
....
}
或是重新定義event()⽅法,將⾃訂事件分派給其它函式或直接在event()中處理,例如:
bool CustomWidget::event(QEvent *event) {
if (event->type() == MyCustomEventType) {
CustomEvent *myEvent = static_cast<CustomEvent *>(event);
// 對⾃訂事件的處理,或呼叫其它函式來處理事件
return true;
}
return QWidget::event(event);
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论