2012-01-02 28 views
11

您有兩個線程a和b。線程a處於永久循環中,監聽阻塞套接字1.線程b也處於永久循環中,監聽阻塞套接字2.套接字1和套接字2都可以在任意時間返回數據,所以線程a可能永遠處於休眠狀態等待數據,而線程b不斷從套接字獲取數據並繼續進行處理。這是背景。Haskell線程通信模式場景

現在假設他們需要共享一本字典。當線程a獲取一些數據(如果有的話)時,它會在處理完一些字典後將一個鍵值對添加到字典中,然後繼續等待更多數據。當線程b從套接字接收數據時,它首先查詢字典,以查看在處理之前是否存在與其接收到的數據有關的信息。字典中沒有刪除,只有插入和查詢(如果這對最終解決方案產生影響,我會感興趣)。

在像Python或C標準的命令式語言,這是很容易通過在這兩個領域中可用的字典,只查詢它一個線程已經獲得了鎖之後做的,所以線程B總是能看到最(以及幾乎)最新的字典。

在Haskell中,我似乎正在努力想出一個很好的實現這種模式。 MVars,一次只能有一個項目,所以它不能將線程放入字典中,因爲可能會發生新的更新,並且直到線程b從MVar中取得它才能夠推送新的字典。另一方面,如果線程b使用MVar發送準備好的信號「OK!」爲了線程化,可能出現這樣的情況:線程a正在其讀取套接字上休眠,所以它將無法發回數據,直到其讀取套接字解除阻塞!也有渠道,但這似乎很混亂,因爲我將不得不繼續發送新的字典,線程B將放棄除最後一個之外的所有。

可行的替代解決方案是簡單地向通道發送更新,並讓線程B爲其自身構建字典。不過,我想知道是否有更好的替代解決方案。

感謝您花時間閱讀這個非常長的問題!

+4

我沒有看到'MVar'的問題。如果A喚醒並獲取新數據,它會嘗試從MVar中取出字典。當它成功時,更新字典,'putMVar'字典,回到睡眠狀態。當B獲得數據時,嘗試'takeMVar',查找放回。那個分解點在哪裏? – 2012-01-02 21:17:13

+1

謝謝!拍攝對不起,這正是我正在尋找的,沒關係。我仍然是個開胃菜。我曾以爲如果放入它就不能取出,只有另一個線程可以。愚蠢的假設在我的腦後!我現在不確定如何解決這個問題? – 2012-01-02 21:19:32

+0

我可以讓它成爲一個答案,您可以接受將問題標記爲已解決,或者如果您願意,可以刪除該問題(我不知道如何,應該有某處有刪除鏈接,我相信)。 – 2012-01-02 21:23:38

回答

10

您可以通過以下方式使用MVar

  • 當線程A獲得新數據,它會嘗試獲取該詞典與takeMVar。當成功時,它會更新字典並將其放回MVar
  • 當線程B獲取數據時,它會嘗試獲取字典takeMVar - 在上述場景中,很少獲取應該平均成功的數據。然後它執行查找並放回字典。

由於哈馬爾指出,它可能最好不要直接使用takeMVarputMVar而是包起來modifyMVar_ RESP。 modifyMVar如果一個線程在使用字典時出現異常,則不會將MVar留空。

在線程A,像

modifyMVar_ mvar (\dict -> putMVar mvar (insert newStuff dict)) 

在線程B所有你需要的是一個簡單的readMVar(感謝指出了這一點再次@hammar)。

+0

對於線程B,我認爲'readMVar'就足夠了(可能更有效),因爲字典沒有被更新。 – hammar 2012-01-03 01:20:01

+0

也許吧。這是非常不可能的,它被搶注和投入之間的異常所擊中,但並非不可能。然後'MVar'可能會變空。另一方面,異常情況很可能不得不殺死整個過程。 – 2012-01-03 01:46:19

+0

'readMVar'的實現使用'mask_',所以我認爲在take和put之間不會發生異常_can_。 – hammar 2012-01-03 01:59:23