2010-07-26 63 views
1

簡單的問題,我想。線程體系結構問題C++消息傳遞

我有一個線程可以響應用戶通過TCP連接時調用的回調函數。如果我接受或拒絕登錄,該回調需要答案。問題是我必須通過異步消息傳遞向安全服務器發送登錄請求並等待響應。

處理這個問題的最佳方法是什麼?現在我有一些代碼只是在回調測試中循環來查看安全服務器是否發送了回覆,並且當它回來時我讀取並返回適當的布爾值。它看起來很粗暴。

TIA

+1

就像我在想也許是一個提升condition_variable或一些這樣的事情。 – shaz 2010-07-26 22:16:17

+0

我注意到最近幾個幾乎相同的問題。這是一個類的項目嗎?只是好奇。 – 2010-07-30 12:14:32

回答

0

想必,你會阻止你的異步調用安全服務器來有效地使之同步。

+0

是的,但阻止如何使用互斥鎖,睡眠和檢查變量?對SecSrv的調用是異步的,所以一旦我打電話,它立即返回,我必須做一些明確的事情來阻止並等待返回消息。我真的很想問一個我認爲是什麼樣的問題,什麼是最平滑的方式來編碼? – shaz 2010-07-26 21:43:02

+0

我無法阻止異步調用,我稍後發送消息並在不同的線程中接收消息。 – shaz 2010-07-27 17:03:37

+0

我在看這裏的示例代碼(http://www.windows-tech.info/13/e64a22df23c19164.php),我沒有看到任何特殊的原因,爲什麼你的回調無法阻止手動重置事件之前返回。 – 2010-07-27 18:28:21

0

在啓動登錄檢查的函數中,在發送消息以請求檢查塊上的內容之後。 Windows事件將起作用,布爾標誌和boost::condition_variableboost::unique_future也會起作用。

在接收來自安全服務器的響應消息的代碼中設置事件或未來或標誌/條件變量。然後這將喚醒初始函數並允許它將適當的響應返回給初始調用者。

1

首先,你需要一個鎖定庫,包含有能力來監控類:

  • 獲得鎖,保證互斥,即只有一個線程可以在任何時候
  • 持有鎖
  • 睡在鎖上,這意味着暫時釋放鎖,並處於休眠狀態,直到可以重新獲取鎖爲止
  • 鎖定信號,通知睡眠線程它們應該被喚醒並重新獲取鎖。只有在持鎖的情況下才能在鎖上發信號。這意味着信號永遠不會喚醒其他線程。通常情況下,信號線程將發出信號,然後立即釋放鎖,允許剛剛發送信號的線程喚醒。喚醒具有將阻塞呼叫返回到休眠狀態的效果,並重新獲得了鎖定。

因此,從某些庫中可用的功能,您需要實現安全服務器代理,該代理使用異步安全服務器來實現同步服務。當同步authenticate()函數被調用一些線程(表示線程1),這是應該發生的事情:

  1. 代理獲取鎖
  2. 代理將請求消息發送到安全服務器
  3. 代理去睡眠,等待結果,線程1已被鎖住和鎖可用
  4. 安全服務器計算結果
  5. 安全服務器發送消息以將結果提供給代理
  6. 代理消息處理函數被調用線程2,線程1仍然受阻
  7. 代理獲取在螺紋鎖2
  8. 代理從消息並將其存儲在一個成員變量
  9. 的檢索結果代理信號在鎖上,導致線程1在睡眠中阻塞以嘗試喚醒,但它不能,因爲線程2仍然保持鎖定(在sleep()函數內,線程2現在在呼叫時被阻塞以獲取鎖)
  10. 代理消息處理程序釋放其鎖
  11. 線程1中的睡眠呼叫重新獲取鎖並返回
  12. 在線程的同步功能1,則立即釋放其鎖定,並返回結果

與線程1重新獲得鎖只能立即釋放它可能看起來毫無意義的最後一部分,但它很重要,因爲這可以確保消息處理程序在同步函數繼續之前完成。

僞代碼,它實際上看起來很簡單,你可能期望:

class SecutityProxy 
{ 
public: 
    SecutityProxy(SecurityServer& server) : m_server(server) 
    {} 
    Result authenticate(username, password) 
    { 
     m_monitor.lock(); 
     m_server.send_message(username, password); 
     m_monitor.sleep(); 
     m_monitor.unlock(); 
     return m_result; 
    } 
    void message_received(message) 
    { 
     m_monitor.lock(); 
     m_result = message; 
     m_monitor->signal(); 
     m_monitor.unlock(); 
    } 
private: 
    SecurityServer& m_server; 
    Monitor m_monitor; 
    Result m_result; 
}; 

注意,此實現不能同時處理多個請求!爲了處理多個併發請求,您需要能夠存儲多個結果。您還需要存儲與每個請求對應的線程的線程句柄。在消息處理程序中,您需要確定哪個線程在任何給定的請求上被阻塞,然後在signal()調用中喚醒相關線程,鎖定庫必須支持該線程。

還請注意,強烈建議實施RAII類來處理監視器上的lock()unlock()調用。