0

當多個線程使用共享數據時,如何在拋出異常時正確處理數據的銷燬?如何在拋出異常時處理共享數據

我正在研究一個應用程序,我希望一個進程在等待從另一個進程通過網絡發送的結果的同時進行工作。我實現創建一個線程等待結果一類,像下面的(實際的代碼太大,張貼在這裏,所以這是一個小例子):

class Notifier { 
    public: 
    Notifier(Client* _client) : value(-1), client(_client) { 
     listener = boost::thread(&Notifer::Listen, this); 
    } 

    void Listen() { 
     try { 
     int rec = client->Receive(); //blocking call to receive data over a socket 
     boost::scoped_lock sl(mutex); 
     value = rec; 
     } catch (...) { 
     cout << "Exception thrown in listener" << endl; 
     } 
    } 

    int Get() { 
     boost::mutex::scoped_lock sl(mutex); 
     return value; 
    } 

    private: 
    int value; 
    boost::mutex; 
    boost::thread listener; 
    Client* client; 
} 

int main() { 
    Client client; //initialize client, connect, etc. 
    Notifier n(client); 
    while(n.Get() < 0) { 
    // do work 
    cout << "Waiting for data" << endl; 
    sleep(1); 
    } 
} 

這工作對我很好,直到我添加異常處理:

int main() { 
    try { 
    Client client; //initialize client, connect, etc. 
    Notifier n(client); 
    while(n.Get() < 0) { 
    // do work 
    cout << "Waiting for data" << endl; 
    sleep(1); 
    throw exception(); 
    } 
    } catch(...) { 
    cout << "Exception thrown in main" << endl; 
    } 
    return 0; 
} 

我得到的錯誤

「助推:互斥鎖的pthread_mutex_lock中失敗:無效的參數」。

我的猜測是,拋出異常時,main函數的堆棧被解開,破壞了互斥鎖。然後Listen函數中的Receive()調用返回並且scoped_lock構造函數試圖鎖定不存在的互斥體,從而導致錯誤。

有人可以證實這確實是怎麼回事?如果是這樣,是否有一種方法可以與線程通信:互斥體不再存在或線程應該終止?還是有更多的異常安全的做我想做的事情?

回答

0

你必須爲Notifier類編寫一個正確的析構函數,它將取消所有阻塞的調用(即解除阻塞client->Receive()),然後終止listener線程。您還需要修改Notifier::Listen()來定期檢查線程終止請求...然後一切都會好的。

+0

只要我實際上可以取消阻止的呼叫,這是一個有趣的想法。我的客戶端類使用Unix'recv'函數,你知道如何解除阻塞嗎? – maditya

+0

發現它 - 有一個['shutdown'](http://linux.die.net/man/2/shutdown)函數。謝謝!我不知道這是可能的。 – maditya

+0

我還有一個問題。如果我按照你的建議使用通告程序的析構函數,我會做例如'客戶端 - >關閉()'。但是這個客戶端並不是真的被通告者「擁有」,它作爲一個參數被傳入,並且在一個更復雜的程序中它可以在通告程序超出範圍後用於其他地方。在這種情況下,我不想關閉客戶端。有沒有辦法區分正常銷燬和異常造成的銷燬,所以我只在第二種情況下關閉客戶端? – maditya

相關問題