2012-08-14 153 views
0

我有這種情況:異步完成處理

void foo::bar() 
{ 
    RequestsManager->SendRequest(someRequest, this, &foo::someCallback); 
} 

其中RequestsManager工作在異步方式:

  • sendRequest將放在一個隊列並返回給調用者
  • 其他線程獲取請求來自隊列的請求並處理它們
  • 當處理一個請求時,回調被稱爲

是否有可能在與SendRequest相同的線程中調用foo :: someCallback?如果沒有,我怎麼能避免「回調限制」:回調不應該做耗時的操作,以避免阻止請求管理器。

回答

1

我可以看到一些方法如何實現它:

A)實施類似於信號處理的策略

當請求處理結束時RequestManager將回調調用置於等待列表上。下次調用SendRequest時,在返回執行之前,它會檢查線程是否有未決的回調並執行它們。這是相對簡單的方法,對客戶端的要求最低。如果延遲不是問題,請選擇它。 RequestManager可以公開API強行檢查掛起回調

B)掛起回調目標線程,並在第三線程執行回調

這會給你所有的告誡真正異步解決方案。它看起來像是目標線程執行被中斷,執行跳入中斷處理程序。在回調之前,目標線程需要被恢復。您將無法從回調內部訪問線程本地存儲或原始線程的堆棧。

3

否 - 調用/回調不能更改線程上下文 - 您必須發出一些信號以在線程之間進行通信。通常情況下,'someCallback'會或者發出發起'SendRequest'調用的線程正在等待的事件,(同步調用)或者推送SendRequest,(因此,可能是它的處理結果)到發送'SendRequest'調用的線程最終會彈出的隊列上(異步)。這取決於發信人的信號是如何閃爍的。

Aynch示例 - 回調可能PostMessage/Dispatcher.Begin將完成的SendRequest調用到GUI線程以顯示結果。

1

取決於「耗時操作」的定義。

經典的方式做到這一點是:

  • 在處理請求,RequestManager應該執行該&foo::someCallback
  • 避免阻塞請求管理器,你可能只是上升這裏面的標誌回調
  • 檢查標誌週期性的線程內,這被稱爲RequestsManager->SendRequest
  • 此標誌將只是一個volatile boolclass foo

如果你想確保,調用線程(foo的)會立即明白,該request已被處理,則需要額外的同步。

在這些線程之間實現(或使用已經實現的)阻塞管道(或使用信號/事件)。我們的想法是:

  • foo的線程執行SendRequest
  • foo開始睡在一些select(例如)
  • RequestManager執行請求和:
    • 電話&foo::someCallback
    • 「喚醒」 foo的線程(通過發送文件描述符中的某個文件foo(使用select))
  • foo是喚醒
  • 檢查volatile bool標誌已經處理的請求
  • 做什麼它需要做
  • 撤銷本級標誌