C++浑浑噩噩的一天:Linux 定时器、多线程、Qt封装

3990阅读 0评论2014-01-07 AoyamaRyo
分类:嵌入式

踏青山丶C++浑浑噩噩的一天

Author:AoyamaRyo
EMail:wind.river.sun@gmail.com

 
        以前,一个类实例总在单个线程中使用,从没考虑过类与多线程的关系。
        现在想写一个Station类,其包含数据采集成员函数(单独一个线程),数据上传成员函数(单独一个线程),该类实例本身存在于主线程(GUI)中。糊里糊涂尝试了一通,最后还是乖乖地用Qt封装的类,其中原理也未深究,为赶时间也颇为无奈。
       可以通过下面这种方式将一个对象的两个成员函数置于两个线程中执行,但该不该这样用也不太清楚。


点击(此处)折叠或打开

  1. pid_t gettid(void)
  2. {
  3.     return syscall(__NR_gettid);
  4. }

  5. class Test
  6. {
  7.  public:
  8.     explicit Test(void){
  9.     }
  10.     void f1(){
  11.         printf("In f1():%x\n",gettid());
  12.         while(1){}
  13.         return;
  14.     }
  15.     void f2(){
  16.         printf("In f2():%x\n",gettid());
  17.         while(1){}
  18.         return;
  19.     }
  20. };

  21. class Test *a;

  22. void *F3(void *p){
  23.     a = new Test;
  24. }

  25. void *F1(void *p){
  26.     (static_cast(p))->f1();
  27. }
  28. void *F2(void *p){
  29.     (static_cast(p))->f2();
  30. }

  31. int main()
  32. {
  33.     pthread_t t1,t2,t3;
  34.     printf("Main thread ID: %x\n",gettid());
  35.     pthread_create(&t3,NULL,F3,NULL);
  36.     sleep(1);
  37.     pthread_create(&t1,NULL,F1,a);
  38.     pthread_create(&t2,NULL,F2,a);
  39.     while(1){}
  40. return 0;
  41. }



结果如下:
Main thread ID: 1440
In f1():1442
In f2():1443
     updated on  sep 19 '14. 这还真是浑浑噩噩呢,完全墙瓷都

 
       (一)封装QThread
 
      定义两个类Uploader、Capturer皆继承QThread,分别重载其run()虚函数完成各自业务逻辑,在Station类中将这两个类的实例定义作成员。而后,对共享的内存区域进行保护。
        读书不多,不知道这个方法有没有问题。
 
 
(二)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 slotsvoid 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_secondm_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_timerNULL, OnTimer_stub, this);
}
void CTimer::StopTimer(){ 
    
pthread_cancel(thread_timer); 
    
pthread_join(thread_timerNULL); //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_secm_second
        
tempval.tv_usecm_microsecond
        
select(0,NULLNULLNULL, &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 

       先就这么办吧。 
上一篇:错误码管理模块的应用
下一篇:阅读IDA的ARM反汇编代码(1)