服務器開發

    

在高性能的網絡程序中,使用得最爲普遍的恐怕要數 「non-blocking IO + IO multiplexing」這種模型,即 Reactor 模式編程

while (!done)
{
int timeout_ms = max(1000, getNextTimedCallback());
int retval = ::poll(fds, nfds, timeout_ms);
if (retval < 0) {
處理錯誤
} else {
處理到期的 timers
if (retval > 0) {
處理 IO 事件
}
}
}安全

=================================================================網絡

1.每一個請求建立一個線程,使用阻塞式 IO 操做。在 Java 1.4 引入 NIO 以前,這是Java 網絡編程的推薦作法。惋惜伸縮性不佳。多線程

2. 使用線程池,一樣使用阻塞式 IO 操做。與 1 相比,這是提升性能的措施。app

3. 使用 non-blocking IO + one loop per thread。即 Java NIO 的方式。
4. Leader/Follower 等高級模式
框架

One loop per thread
此種模型下,程序裏的每一個 IO 線程有一個 event loop (或者叫 Reactor),用 於 處 理
讀寫和定時事件(不管週期性的仍是單次的),代碼框架跟第 2 節同樣。
這種方式的好處是:
� 線程數目基本固定,能夠在程序啓動的時候設置,不會頻繁建立與銷燬。
� 能夠很方便地在線程間調配負載。
event loop 表明了線程的主循環,須要讓哪一個線程幹活,就把 timer 或 IO channel
(TCP connection) 註冊到那個線程的 loop 裏便可。對實時性有要求的 connection 可
以單獨用一個線程;數據量大的 connection 能夠獨佔一個線程,並把數據處理任務分
攤到另幾個線程中;其餘次要的輔助性 connections 能夠共享一個線程。
對於 non-trivial 的服務端程序,通常會採用 non-blocking IO + IO multiplexing,每一個
connection/acceptor 都會註冊到某個 Reactor 上,程序裏有多個 Reactor,每一個線程至多
有一個 Reactor。
多線程程序對 Reactor 提出了更高的要求,那就是「線程安全」。要容許一個線程往別
的線程的 loop 裏塞東西,這個 loop 必須得是線程安全的。
線程池
不過,對於沒有 IO 光有計算任務的線程,使用 event loop 有點浪費,我會用有一種
補充方案,即用 blocking queue 實現的任務隊列(TaskQueue):
blocking_queue<boost::function<void()> > taskQueue;
void worker_thread()
{
while (!quit) {
boost::function<void()> task = taskQueue.take();
task(); // 在產品代碼中須要考慮異常處理
}
}
用這種方式實現線程池特別容易:
啓動容量爲 N 的線程池:
int N = num_of_computing_threads;
for (int i = 0; i < N; ++i) {
create_thread(&worker_thread); // 僞代碼:啓動線程
}
4
// 線程安全的阻塞隊列
// this blocks使用起來也很簡單:
boost::function<void()> task = boost::bind(&Foo::calc, this);
taskQueue.post(task);
上面十幾行代碼就實現了一個簡單的固定數目的線程池,功能大概至關於 Java 5 的
ThreadPoolExecutor 的某種「配置」。固然,在真實的項目中,這些代碼都應該封裝到一個
class 中,而不是使用全局對象。另外須要注意一點:Foo 對象的生命期,個人另外一篇博客
《當析構函數遇到多線程——C++ 中線程安全的對象回調》詳細討論了這個問題
http://blog.csdn.net/Solstice/archive/2010/01/22/5238671.aspx
除了任務隊列,還能夠用 blocking_queue<T> 實現數據的消費者-生產者隊列,即 T 的
是數據類型而非函數對象, queue 的消費者(s)從中拿到數據進行處理。這樣作比 task queue
更加 specific 一些。
blocking_queue<T> 是多線程編程的利器,它的實現可參照 Java 5 util.concurrent 裏的
(Array|Linked)BlockingQueue,一般 C++ 能夠用 deque 來作底層的容器。Java 5 裏的代
碼可讀性很高,代碼的基本結構和教科書一致(1 個 mutex,2 個 condition variables),
健壯性要高得多。若是不想本身實現,用現成的庫更好。(我沒有用過免費的庫,這裏就不
亂推薦了,有興趣的同窗能夠試試
Intel Threading Building Blocks 裏 的
concurrent_queue<T>。)
概括
總結起來,我推薦的多線程服務端編程模式爲:event loop per thread + thread pool。
� event loop 用做 non-blocking IO 和定時器。
� thread pool 用來作計算,具體能夠是任務隊列或消費者-生產者隊列。異步

 

 

 

=========================================================================函數

 eventloop 用做 non-blockingIO 和定時器。工具

 threadpool 用來作計算,具體能夠是任務隊列或消費者-生產者隊列oop

任務對列,生產消費者 線程池

TaskQueue、Producer-Consumer Queue、 CountDownLatch 

PTHREAD_MUTEX_ERRORCHECK排錯

 

條件變量是很是底層的同步原語, 不多直接使用, 通常都是用它來實現高層的同施步,措 如 BlockingQueue 或 CountDownLatch

 

線程 分析工具如 Intel Thread Checker 和 Valgrind-Helgrind 等能識別 pthreads 調用,並依據 happens-before 關係 [Lamport 1978] 分析程序有無 data race

使用互斥器的條件變量的慣用手法 (idiom),關鍵是 RAII

 

 同步線程處理業務邏輯,異步線程處理IO

異步線程只有一個,由主線程當

每一個線程開啓一個事件loop ,及epoll_wait             

microhttp, libpg, libdrizzle, quickfix

https://google-glog.googlecode.com/files/glog-0.3.3.tar.gz

blocking_queue<T> 是多線程編程的利器,它的實現可參照 Java 5 util.concurrent 裏的(Array|Linked)BlockingQueue,一般 C++ 能夠用 deque 來作底層的容器

相關文章
相關標籤/搜索