(二)Station的成员函数置于单独线程
将完成数据采集以及上传功能的Station成员函数capture()、upload()置于单独线程中(使用pthread_create()创建线程)。遇到的问题见示例代码中的注释。
///MainWindow.h
#include
#define gettid() syscall(__NR_gettid)
classMainWindow : public QMainWindow{
Q_OBJECT
public:explicit MainWindow(QWidget *parent = 0);
~MainWindow();
//void*hdlThread(void *args); //只有类的静态函数能作为pthread_create()创建线程的回调函数
//静态函数没有this指针。瞎胡闹,有就出乱子了。
//只好将Station实例指针(this)保存在文件变量(struct ThreadArgs thrArg)中。
public slots: void sltTestTimer();
//signals:
// voidsigTimeOut(); //signals限定的成员函数是“protect”属性,非MainWindow成员函数无法通过调用
//emit sigTimeOut() ,企图调用其sltTestTimer()槽函数。
private:Ui::MainWindow *ui;
pthread_tmChildTid;
};
///MainWindow.c
QTimer *tTimer;
struct ThreadArgs{
MainWindow*__this;
int interval;
};
struct ThreadArgs thrArg;
#ifdef TEST
void *hdlThread(void *arg){ //线程回调函数,但该函数中tTimer->start();是无法执行的,它需要事件 //循环,需要在QThread创建的线程中执行。
//qDebug()<< (unsigned int)(thrArg.__this) <<"\n";
tTimer = new QTimer;tTimer->setInterval(thrArg.interval);
QObject::connect(tTimer,SIGNAL(timeout()),
thrArg.__this,SLOT(sltTestTimer()));
tTimer->start();
while(1){}
}
#else
voidsigroutine(int signo){ //所以使用Linux系统提供的定时器,实现周期性作业
switch(signo){
caseSIGALRM:
thrArg.__this->sltTestTimer(); ///通过打印线程tid发现,这个槽函数总是运行在主线程中
///这不是乐见的,但却是理所当然的,signal()、sigaction()函数设定的是
///整个进程的信号处理,可以通过phread_sigmask()在其他线程中屏蔽该
///SIGALARM信号。但这样做真的好吗?感觉有些跛脚。
signal(SIGALRM,sigroutine);
break;
}
return;
}
void *hdlThread(void *arg){
struct itimerval value, ovalue;
signal(SIGALRM, sigroutine);
value.it_value.tv_sec = thrArg.interval;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = thrArg.interval;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);
for(;;);
}
#endif
int threadId;
QReadWriteLockstrLock;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(newUi::MainWindow){
ui->setupUi(this);
thrArg.__this = this;
thrArg.interval = 4;
int ret =pthread_create(&mChildTid,NULL,hdlThread,NULL);
}
MainWindow::~MainWindow(){ delete ui;}
void MainWindow::sltTestTimer(){
QWriteLockertmpLock(&strLock); //利用C++类构造、析构函数特性自动解锁临界资源
threadId = gettid();
qDebug()<< "Timer is working in thread: "<< threadId <<"...\n";
}
/*-------------------------------不用信号,实现定时器,只要稍加修改传入回调函数即可-------------------------*/
头文件:
#ifndefCTIMER_H_
#define CTIMER_H_
#include
#include
classCTimer
{
private:pthread_t thread_timer;
long m_second, m_microsecond;
static void *OnTimer_stub(void *p)
{
(static_cast<CTimer*>(p))->thread_proc(); ///去掉this指针,否则pthread_create()不认该函数。
}
void thread_proc();
virtual void OnTimer();
public:CTimer();
CTimer(long second, long microsecond);
virtual~CTimer();
voidSetTimer(longsecond,long microsecond);
void StartTimer();
voidStopTimer();
};
#endif /* CTIMER_H_ */
源文件:
#include"CTimer.h"
#include
#include
#include
#include
usingnamespace std;
//////////////////////////publicmethods//////////////////////////
CTimer::CTimer(): m_second(0), m_microsecond(0){}
CTimer::CTimer(long second, long microsecond) : m_second(second), m_microsecond(microsecond){}
CTimer::~CTimer(){}
void CTimer::SetTimer(long second, long microsecond){
m_second = second;
m_microsecond =microsecond;
}
void CTimer::StartTimer(){
pthread_create(&thread_timer, NULL, OnTimer_stub, this);
}
void CTimer::StopTimer(){
pthread_cancel(thread_timer);
pthread_join(thread_timer, NULL); //wait the thread stopped
}
//////////////////////////privatemethods//////////////////////////
voidCTimer::thread_proc(){
while (true) {
OnTimer(); ///问题变成,OnTimer()-last-end至OnTimer-next-start的时间间隔
///为tempval。期望的是OnTimer()-last-start至OnTimer-next-start
///的时间间隔为tempval,如此必然要使用线程间通信。
/* 加锁、解锁的时间消耗对该系统而言不足挂齿。可以用锁实现:
添加成员:QMutex mTimerLock;
void waitToStart(){
mTimerLock.lock();
}
bool isReadyToStart(){
return mTimerLock.trylock();
}
修改thread_proc()函数,睡眠结束后只解锁mTimerLock,继续休眠。
只是再注意一下回调函数处理时间比定时时间长的情况。
*/
pthread_testcancel();
structtimeval tempval;
tempval.
tv_sec=
m_second;
tempval.
tv_usec=
m_microsecond;
select(
0,
NULL,
NULL,
NULL, &tempval);
}
}
void CTimer::
OnTimer(){
cout<<
"Timer once..."<
}
(三)老老实实用QThread、QTimer封装吧
Qt中类在哪个线程中实例化,其槽函数的运行空间就在该线程。
qDebug() <<
"Main thread id: " <<
gettid() <<
"\n";
mThrCapture =
new QThread(
0);
mTmrCapture =
new QTimer(
0);
TimerHandler *tmrHandler =
new TimerHandler(
0);
tmrHandler->moveToThread(
mThrCapture);
mTmrCapture->moveToThread(
mThrCapture);
mTmrCapture->setInterval(
3000);
//这两个槽函数都是打印线程ID
connect(
mTmrCapture,
SIGNAL(timeout()),
this,
SLOT(sltTmrCapture()));
///this指向的对象在主线程中创建,
///所以该函数在主线程空间中执行。
connect(
mTmrCapture,
SIGNAL(timeout()), tmrHandler,
SLOT(sltTmrGreek()));
///tmrHandler被moveToThread至子线程,
///故该函数在子线程空间中执行。
connect(
mThrCapture,
SIGNAL(started()),
mTmrCapture,
SLOT(start()));
mThrCapture->start();
结果如下:
Main threadid: 6259
6260
6259
先就这么办吧。