2012-11-11 23 views
2

我想在Linux下用C++編寫一個庫,它將幫助應用程序使用某種協議(實際上是FastCGI)。該庫將偵聽套接字(TCP或Unix),接收請求,將它們轉發給用戶代碼,併發送由所述用戶代碼生成的響應。C++/Linux:你如何編寫一個使用套接字的線程安全庫?

套接字上會有很多連接,並且每個連接都會攜帶很多請求(可能同時存在交叉機制)。用戶代碼(使用庫)很可能是多線程的,以並行處理多個請求。

我希望我的庫很健壯,儘可能少地假設/要求用戶代碼,包括使用的多線程類型。據我所知,Linux中的clone()函數可以用幾十種不同的方式分支進程 - 有或沒有共享內存,共享文件句柄等。如何實現多線程的決定應由用戶決定。

這使我感到困惑,因爲庫代碼可以突然發現它自己,並且代碼的多個副本可以突然從相同的套接字讀取並處理相同的請求。更糟糕的是,父進程可能會終止,只留下子進程,進而產生更多的子進程,甚至可能在不同的進程名稱空間中 - 這是一團糟。

有哪些Linux工具可以幫助協調需要訪問相同外部資源(套接字)的相同代碼的所有副本?什麼是實現這種線程安全庫的標準方式?我必須自己選擇一種線程模型,並將其強加給我的圖書館的消費者嗎?

+2

我們一口氣在談論線程,'fork' *和*'clone' ......這是一個很高的命令。 –

+0

@KerrekSB:正如我所說的 - 我希望這個選擇(線程/ fork/clone)與我的庫的用戶一起駐留,並且庫應該能夠處理它的使用情況......如果可能的話,課程。 :P我也在某處讀到'fork()'實際上是'clone()'和一組特定的標誌。 –

+0

@KerrekSB:P.S.我對Windows非常熟悉,但我還沒有在Linux上寫過任何可能顯示的內容。我試圖把我的大腦圍繞在Linux的做事方式上。 –

回答

0

不要使用直接clone(儲備clone實施者線程庫的pthread)。不要使用很多fork -s(可能沒有)。去使用pthread-S。

您可以看看libonion庫的設計。它很小,實現HTTP服務器協議,因此與您的目標非常相似。

libonion爲用戶提供了創建或不創建請求線程的各種模式。

您可以選擇類似於libonion-s的選項來創建或不是每個FastCGI請求的新線程。

您可能想要使用一些事件循環庫,如libeventlibev(圍繞poll(2) -ing循環)。

在開始編碼之前,請讀好書,特別是Advanced Linux Programmingtutorial on Pthread-s

另外,研究幾個免費軟件庫的源代碼類似於你的目標。

0

如果看起來正好相切,我建議在每個處理器的基礎上,在單線程上實施fastcgi。

原因:

  1. 更強大。
  2. 避免與多線程相關的上下文切換開銷,並保護您免受併發死鎖等問題的困擾。
  3. 避免過程fork()成本(雖然相當輕便全部加起來) 並且保護您免於處理潛在的小孩殭屍進程以及其他令人頭痛的問題。

這將使你實現使用FastCGI的接口的選擇:

  1. 非阻塞式同步I/OReactor設計模式):塊,直到讀或寫請求進入,傳遞請求到 適當的處理程序,然後阻塞,直到下一個請求到達
  2. 異步I/OProactor設計模式):通過讀取和寫入請求到操作系統,其中O/S支持I/O 完成事件。在Windows上,這將是IO completion ports 和在Linux上,如epoll()
+0

如果每個FastCGI請求可以很快得到回答(小於100毫秒),那麼這可能是一個好主意。如果OP也想處理一些罕見的,但昂貴的 - 即。響應速度慢FastCGI請求 - 例如需要超過一秒鐘的CPU時間,或者需要進行許多複雜且昂貴的數據庫查詢,這可能不那麼明顯.... –

+0

這確實是一個切線。如果我不清楚,我不想強​​迫圖書館的消費者做任何事情。如果他們想爲每個處理器產生一個單獨的線程 - 那很好。如果他們想要產生100個工作進程 - 那也很好。如果他們想產生5個20線程的進程,交替使用基於月相 - 這也很好。它可以完成嗎? –

+0

我的意思是 - 我不希望我的圖書館在所有東西上產卵。消費者應該對此負責。消費者應該實現主應用程序循環。我的圖書館應該快樂地標記,並在詢問時吐出一兩個要求。 –

相關問題