2009-07-01 65 views
0

我有一個線程使用select系統調用來監控串行端口,線程的run函數如下:用select()系統調用語句關閉一個線程?

void <ProtocolClass>::run() 
{ 
    int fd = mPort->GetFileDescriptor(); 
    fd_set readfs; 
    int maxfd=fd+1; 
    int res; 

    struct timeval Timeout; 
    Timeout.tv_usec=0; 
    Timeout.tv_sec=3; 


    //BYTE ack_message_frame[ACKNOWLEDGE_FRAME_SIZE]; 
    while(true) 
    { 
     usleep(10); 
     FD_ZERO(&readfs); 
     FD_SET(fd,&readfs); 
     res=select(maxfd,&readfs,NULL,NULL,NULL); 
     if(res<0) 
      perror("\nselect failed"); 
     else if(res==0) 
         puts("TIMEOUT"); 
     else if(FD_ISSET(fd,&readfs)) 
     {//IF INPUT RECEIVED 
       qDebug("************RECEIVED DATA****************"); 
     FlushBuf(); 
     qDebug("\nReading data into a read buffer"); 
     int bytes_read=mPort->ReadPort(mBuf,1000); 
     mFrameReceived=false; 
     for(int i=0;i<bytes_read;i++) 
     { 
      qDebug("%x",mBuf[i]); 
     } 



     //if complete frame has been received, write the acknowledge message frame to the port. 
     if(bytes_read>0) 
     { 
       qDebug("\nAbout to Process Received bytes"); 
      ProcessReceivedBytes(mBuf,bytes_read); 
      qDebug("\n Processed Received bytes"); 
      if(mFrameReceived) 
     { 
     int no_bytes=mPort->WritePort(mAcknowledgeMessage,ACKNOWLEDGE_FRAME_SIZE); 
      }//if frame received 
     }//if bytes read > 0 
     } //if input received 
    }//end while 
} 

問題是,當我從這個線程退出,使用

delete <protocolclass>::instance(); 

該程序崩潰與malloc內存損壞glibc錯誤。在用gdb檢查覈心時發現它退出正在處理數據的線程以及錯誤。協議類的析構函數如下所示:

<ProtocolClass>::~<ProtocolClass>() 
{ 
    delete [] mpTrackInfo; //delete data 
    wait(); 
    mPort->ClosePort(); 
    s_instance = NULL; //static instance of singleton 
    delete mPort; 
} 

這是由於select?涉及到select時,銷燬對象的語義是否改變?有人可以建議一種乾淨的方式來銷燬涉及select調用的線程。

謝謝

+0

還在爲你的子系統使用單身! – TimW 2009-07-01 07:13:33

+0

是的,但並行工作在其他實現。我是唯一的人,必須處理文檔,測試和開發。並回答我的領導 – rocknroll 2009-07-01 08:57:19

回答

3

我不確定你使用了什麼線程庫,但是你應該用這樣或那樣的方式告訴線程它應該退出,而不是殺死它。

最簡單的方法是保持線程應該退出時設置爲true的布爾值,並使用select()調用的超時定期檢查它。

ProtocolClass::StopThread() 
{ 
    kill_me = true; 

    // Wait for thread to die 
    Join(); 
} 

ProtocolClass::run() 
{ 
    struct timeval tv; 
    ... 
    while (!kill_me) { 
    ... 
    tv.tv_sec = 1; 
    tv.tv_usec = 0; 
    res = select (maxfd, &readfds, NULL, NULL, &tv); 

    if (res < 0) { 
     // Handle error 
    } 

    else if (res != 0) { 
     ... 
    } 
} 

你也可以建立一個管道並將其包含在readfds,然後只寫從另一個線程什麼東西。這將避免每秒醒來,並毫不拖延地拖下線。當然

而且,你不應該使用這樣的一個布爾變量沒有一些類型的鎖,...

+0

好的一般方法。確保在返回之前進行清理,以便調用線程只需停止線程。 – stefaanv 2009-07-01 07:07:44

0

刪除它之後線程是否仍然在看mpTrackInfo?

沒有看到代碼很難。但我會認爲析構函數應該做的第一件事就是等待任何線程死掉(最好用某種形式的join()來確保它們全部被佔用)。一旦他們死了,你可以開始清理數據。

0

你的線程不僅僅是一些成員內存的更多,所以才刪除,並指望析構函數不夠。因爲我不知道QT線程我認爲這個鏈接可以讓你用自己的方式: trolltech message

0

兩個可能的問題:

  • 什麼是mpTrackInfo?您在等待線程退出之前刪除它。線程是否在某個地方使用了這些數據,甚至在它被刪除之後呢?
  • 線程如何知道它應該退出? run()中的循環似乎永遠運行,這會導致析構函數中的wait()永遠等待。