2011-03-22 125 views
1

我有以下程序:問題在程序執行的線程

#include "stdafx.h" 
#include <boost/thread/thread_time.hpp> 
#include <boost/thread/thread.hpp> 
#include <iostream> 
using namespace std; 

class DogDoor { 
    bool open; 
public: 
    DogDoor() 
    { 
     this->open = false; 
    } 
    void Open() 
    { 
     cout << "The dog door opens" << endl << endl; 
     open = true; 
    } 
    void close() 
    { 
     cout << "The dog door closes" << endl << endl; 
     open = false; 
    } 
    bool isOpen() 
    { 
     return open; 
    } 
}; 

class Remote { 
    DogDoor* door; 
public: 
    Remote(DogDoor* door) 
    { 
     this->door = door; 
    } 
    void pressButton() 
    { 
     cout << "Pressing the remote button" << endl; 
     if(door->isOpen()) 
     { 
      door->close(); 
     } 
     else 
     { 
      door->Open(); 
      // close after 5 seconds 
      boost::posix_time::seconds workTime(5); 
      boost::this_thread::sleep(workTime); 
      door->close(); 
     } 
    } 
}; 

void threadFunc(Remote* r) 
{ 
    r->pressButton(); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    DogDoor* door = new DogDoor(); 
    Remote* remote = new Remote(door); 

    cout << "Fido barks to go outside" << endl; 
    boost::thread workerThread(threadFunc, remote); 

    cout << "Fido has gone outside" << endl; 

    cout << "Fido is all done..." << endl; 

    cout << "Fido is back inside" << endl; 

    workerThread.join(); 

    delete door; 
    delete remote; 

    return 0; 
} 

我希望程序打印:

Fido barks to go outside 
Pressing the remote button 
The dog door opens 
Fido has gone outside 
Fido is all done... 
Fido is back inside 
// and then after 5 seconds it should print this 
The dog door closes 

但我實現它會打印這樣的,我不知道如何使它打印良好:

Fido barks to go outside 
Fido has gone outside 
Fido is all done... 
Fido is back inside 
Pressing the remote button 
The dog door opens 
// this after 5 seconds 
The dog door closes 

回答

3

你需要讓主線程等待,直到門被打開:

class DogDoor 
{ 
    bool open; 
public: 
    // If you want to go through this door you should call 
    // this method. If the door is not open you are suspended. 
    // until somebody opens the door. 
    void goThroughDoor() 
    { 
     boost::unique_lock<boost::mutex> lock(mut); 
     while(!open) 
     { 
      // Note this is a while loop here. 
      // Just because all the waiting threads are un-sespended when the 
      // door is opened, it does not mean that they will get scheduled 
      // to run before the door closes. So after the thread wakes up and 
      // starts to run we need to re-check if the door is still open. 
      // 
      // If it took to long to wake up, then we have to wait again for 
      // the door to be opened. 
      // 
      // Thus this would be a good place to bark. 
      // Which may cause the remote button to be pushed. 
      // 
      waiter.wait(mut); 
     } 
    } 


    DogDoor() 
    { 
     this->open = false; 
    } 
    void Open() 
    { 
     boost::unique_lock<boost::mutex> lock(mut); 
     cout << "The dog door opens" << endl << endl; 
     open = true; 

     waiter.notify_all(); 
    } 
    void close() 
    { 
     boost::unique_lock<boost::mutex> lock(mut); 
     cout << "The dog door closes" << endl << endl; 
     open = false; 
    } 
    bool isOpen() 
    { 
     boost::unique_lock<boost::mutex> lock(mut); 
     return open; 
    } 


    private: 
     boost::condition_variable waiter; 
     boost::mutex    mut; 

}; 

現在,您需要修改主要以確保狗調用goThroughDoor()。

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    DogDoor* door = new DogDoor(); 
    Remote* remote = new Remote(door); 

    cout << "Fido barks to go outside" << endl; 
    boost::thread workerThread(threadFunc, remote); 

    // This will suspend this thread if the door is locked. 
    // When the door is opened the thread will resume.  
    door->goThroughDoor(); 


    cout << "Fido has gone outside" << endl; 

    // Should check the door is open 
    // When Fido tries to come in. If it is closed he will be suspended. 
    // And thus will not get back in. (Note he should have a way of barking 
    // if he is blocked but that I leave to you).  
    door->goThroughDoor(); 
    cout << "Fido is all done..." << endl; 

    cout << "Fido is back inside" << endl; 

    workerThread.join(); 

    delete door; 
    delete remote; 

    return 0; 
} 
+0

非常感謝你 – Kobe 2011-03-22 22:25:38

4

沒有說你的開始線程必須馬上執行;在join()調用顯式丟棄CPU之前,它可能不會被調度運行。雖然你可以嘗試調用Boost的道德等效yield(),在完整的程序中沒有任何東西可以保證線程想要實際運行會運行

爲確保您等待子線程執行,您需要使用一些thread synchronization工具(例如互斥鎖或條件變量),以便您的子線程可以通知主線程它已完成任務。如果您將電話移至join()更靠近產卵程序的位置,則可以確定線程已完成,但這可能僅適用於玩具應用程序。在非平凡的應用程序中,您需要使用mutexcondition variable來表示線程之間特定的「已完成作業」條件。

+0

謝謝,我會嘗試使用syncronization – Kobe 2011-03-22 22:14:55

3

首先,值得注意的是,從大多數觀點來看,這幾乎是線程/線程的最壞可能使用。特別是,兩個線程都不能自己做任何事情 - 一個線程中的所有內容都需要與另一個線程中的某些內容進行同步。

這幾乎是你遇到的問題 - 你沒有同步到你需要的任何地方。你的序列需要是這個樣子:

Fido barks 
ask door to open 
wait for confirmation that door has opened 
Fido leaves 
Fido returns 
ask door to close 
wait for confirmation that door has closed 
join 
exit 

從本質上講,一個線程中的每一個動作依賴於其他線程的東西,所以即使你有兩個線程,沒有它可以並行執行。