線程池網絡編程

多線程編程中,每有一個新連接時就會創建一個新的線程去維護連接進行收發數據,但是這會有一個問題,就是頻繁的線程創造結束會使系統內核的負擔加重,對於執行任務的效率也相對低下,因爲還要多出創造線程的時間。
  那麼如何提高效率,減輕內核的負擔呢?我們知道主要原因是由於頻繁的創建線程。想要改善效率 不可能選擇不創建線程。那隻能讓線程創建的時間提前,並且不會頻繁的再結束再創建。因此就有了線程池的提出。
   線程池就是一個進程在最開始先把工作 線程全部創建完畢,只有當需要用到某個線程的時候才工作。
   不難想到要用阻塞的方式在每個線程的開始處堵住。在觸發某些特定條件,例如主線程接受到新的連接時使一個堵塞住的函數線程變成運行狀態去處理事件。並且這個函數線程應該是個死循環,即處理完某件事情後不應該結束,而是進入下一次循環 的堵塞狀態,然後 等待之後的任務,這樣就不會往復的創建新線程了。
    因此大概的框架就是這樣的。
    
     函數線程
   {
    while(1)
   {
      阻塞;
       
      工作;

   }
    

  }

  主線程
 {
   創建n個函數線程。

    while
    接受任務
    使一個阻塞條件開發,某個線程可以工作  
  }


 }

因此具體使用的阻塞方式應該選擇信號量比較合適。
例如 主線程初始化信號量爲0,然後創建3個線程,每個線程裏的while裏開始爲p操作,當主線程接受到鏈接後,進行一次v操作,然後3個線程中的某個線程就會競爭到一次p操作,然後執行,執行完畢後,進入下一次循環,堵在p操作上。

但上面最多同時處理三個鏈接,如果同時發起鏈接的客戶端超過了3個,那麼無論主線程怎麼v,都無法使線程獲取到那次的鏈接,因此要維護一個緩衝區的隊列去存儲鏈接描述符,假如緩衝區的多列大小有10個,那麼同時就能接受13個鏈接,注意不是同時處理13個鏈接,而是處理3個鏈接,其餘10個鏈接暫時存入緩衝區,如果前13個鏈接都沒有處理完畢,第十四個鏈接來了那麼只能丟棄了。因此可以把緩衝區設置大些。

用數組簡單的模擬緩衝區隊列,並用幾個函數封裝主要的操作。


主線程和函數線程



用一個客戶端fork 20次去連接服務器 測試結果




結果




10秒後




 其實進程池和線程池的思想也是一樣,一開始fork很多子進程阻塞住,利用進程間的信號量控制機制。
然後父進程負責接受鏈接,v操作,不過這裏值得注意的是,鏈接描述符c的傳遞,不像是線程的那樣簡單,線程由於都在一個進程中,共享一個pcb,描述符就是pcb裏某個結構體數組的下標,所以描述符是啥就是啥。
但進程間就不一樣,比如a進程的 描述符5 和  b進程的描述符5不是一個東西,雖然數字都是5,但是它們的pcb各不相同,5只表示pcb裏某個成員數組的下標。因此需要特殊的傳遞方式,有興趣可以參考《linux高性能服務器編程
》13.9的內容,在此不多重複。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章