2011-05-07 61 views
2

async_write()被禁止從不同線程同時調用。它通過塊使用async_write_some來發送數據,並且這樣的塊可以被交織。因此,用戶不必同時致電async_write()並行的async_write。有沒有等待解決方案?

有沒有比這個僞代碼更好的解決方案?

void send(shared_ptr<char> p) { 
    boost::mutex::scoped_lock lock(m_write_mutex); 
    async_write(p, handler); 
} 

我不喜歡這個主意,以阻止其他線程了相當長的時間(有50MB的〜在發送我的應用程序)。

可能是這樣的事情會工作?

void handler(const boost::system::error_code& e) { 
    if(!e) { 
    bool empty = lockfree_pop_front(m_queue); 
    if(!empty) { 
     shared_ptr<char> p = lockfree_queue_get_first(m_queue); 
     async_write(p, handler); 
    } 
    } 
} 

void send(shared_ptr<char> p) { 
    bool q_was_empty = lockfree_queue_push_back(m_queue, p) 
    if(q_was_empty) 
    async_write(p, handler); 
} 

我更願意找到一個隨時可以使用的食譜食譜。處理無鎖並不容易,會出現很多細微的錯誤。

+2

假設傳輸儘可能快地運行,那麼交織來自多個線程的數據的優點是什麼?它不會加快總傳輸速率,並且線程平均不會更快完成。 – 2011-05-07 11:54:31

+0

傳遞給async_write()的整個緩衝區必須作爲連續塊發送。它有一些結構。想象一下像http-answer一樣的標題和文件內容。如果有併發的async_write(),結構將會被破壞。 – user222202 2011-05-07 17:44:05

+0

來自boost文檔: 此操作是通過對流的async_write_some函數的零個或多個調用實現的,稱爲合成操作。程序必須確保該流不會執行其他寫入操作(例如async_write,流的async_write_some函數或執行寫入的任何其他組合操作),直到此操作完成。 – user222202 2011-05-07 17:45:16

回答

3

ASYNC_WRITE()禁止以 從不同 線程

本聲明同時調用是不太正確的。應用程序可以同時自由調用async_write,只要它們位於不同的socket對象上即可。

有沒有比這個 僞代碼更好的解決方案?

void send(shared_ptr<char> p) { 
    boost::mutex::scoped_lock lock(m_write_mutex); 
    async_write(p, handler); 
} 

這可能是沒有辦成,因爲你馬上async_write回報打算什麼。如果您打算在整個寫操作期間鎖定互斥鎖,則需要將scoped_lock保持在範圍內,直到調用完成處理程序。

這個問題有更好的解決方案,圖書館內置了支持使用strand的概念。它非常適合這種情況。

甲鏈被定義爲事件的嚴格順序 調用 處理程序(即,沒有併發 調用)。線的使用允許 程序在多線程 程序中的執行,而不需要明確的 鎖定(例如使用互斥體)。

在此處使用顯式鏈將確保您的處理程序僅由調用了io_service::run()的單個線程調用。用你的例子,m_queue成員將受到一個鏈的保護,確保原子訪問傳出的消息隊列。在向隊列添加條目之後,如果大小爲1,則表示沒有未完成的async_write操作正在進行中,並且應用程序可以啓動一個包裝通過鏈。如果隊列大小大於1,則應用程序應等待完成async_write。在async_write完成處理程序中,從隊列中彈出一個條目並根據需要處理任何錯誤。如果隊列不爲空,則完成處理程序應從隊列的前端啓動另一個async_write

這是一個非常乾淨的設計,可以在類中使用互斥量,因爲它使用內置的Asio構造。這other answer I wrote有一些代碼實現這種設計。

+1

你確定'strand'嗎?我相信問題是如何異步發送非交錯數據包。我相信和我有同樣的問題,他有一個線程調用'io_service :: run()',還有一些其他線程想寫一些響應。 例如,2個其他線程在同一個'socket'對象上發出'async_write()',實際調用'async_write_some()'的次序是未定義的。 只有'strand'保證只有這個寫操作的完成處理程序纔會被序列化,這是因爲只有一個線程調用了'io_service :: run()'。 – 2012-11-28 15:38:56

+0

@DragomirIvanov是這條鏈對於確保訪問用於將調用序列化到'async_write'的傳出消息隊列是必需的。我已經更新了我的答案以澄清。 – 2013-11-18 19:18:46

1

我們通過將要寫入的數據的單獨隊列保存在套接字對象中解決了此問題。當要寫入的第一條數據「排隊」時,我們啓動一個async_write()。在我們的async_write的完成處理程序中,如果仍有數據要傳輸,我們將開始後續的async_write操作。

+0

這個。根據Sam Miller的回答建議使用鏈可以確保您不會在發送隊列上獲得併發訪問權限,這意味着不需要互斥體。因此,如果正確實施,此解決方案將按照要求等待。 – ComicSansMS 2013-09-06 12:26:00

相關問題