Operating System-Thread(5)彈出式執行緒&&使單執行緒程式碼多執行緒化會產生那些有關問題

劍西樓發表於2017-02-22
Operating System-Thread(5)彈出式執行緒&&使單執行緒程式碼多執行緒化會產生那些問題

本文主要內容

  1. 彈出式執行緒(Pop-up threads)
  2. 使單執行緒程式碼多執行緒化會產生那些問題

一、彈出式執行緒(Pop-up threads)

以在一個http到達之後一個Service的處理為例子來介紹彈出式執行緒。

上面的例子中傳統的做法有可能是在Service中有一個執行緒一直在等待request的到達,等request到達後這個執行緒會開始檢查請求最後在進行處理。當這個執行緒在處理request的時候,後面來的request會被block,一直到執行緒處理完當前request為止。如下圖所示。

彈出式執行緒的處理方法:當有新的請求到達時,馬上建立一個執行緒去處理這個請求(彈出pop-up thread).

彈出式執行緒的優勢:

  1. 執行緒是全新的,沒有歷史,建立很快
  2. request沒有被block,請求到達到開始處理之間的延遲非常小

在使用彈出式執行緒時需要額外考慮一下,這個執行緒是應該執行在那裡比較好。使用者空間還是核心空間。將執行緒放在核心相對會比較容易,但是因為在核心,如果該執行緒出問題,危害性將比使用者空間的執行緒大。

 二、使單執行緒程式碼多執行緒化

一些既有的程式碼都是基於單執行緒的,如果將其修改為支援多執行緒會產生那些後果呢,下面簡單一一做一下分析。

2.1 多執行緒共享變數

圖示:

n在t1、t2之間共享:

  1. T1呼叫Check程式檢查自己的狀態,得的n=1這個狀態
  2. 在T1得到狀態使用n之前cpu被排程給了T2。
  3. T2呼叫Check程式檢查自己的狀態,得的n=2這個狀態
  4. CPU再次被排程到T2,這個時候n已經等於2了,產生了錯誤的結果。

上面的問題是可以被優化的,讓T1和T2取消這個對N的共享,讓其各自維護自己的狀態碼N1,和N2即可避免上述問題。

2.2 重複進入

類似於上面的共享問題,一個Library提供一個功能,在一個執行緒進入該Library後沒有返回之前另外一個執行緒又進入了,會產生什麼問題呢。

比如這個Library在請求沒有返回之前將資料放入buffer,那麼這個時候另外一個執行緒進入這個Library會將原有buffer的資料重置,從而對第一個執行緒的執行造成不可預估的後果。

這種問題可以讓Library提供一個標誌位,當這個Library處於呼叫狀態時,設定標誌位,這樣後續的請求將會被block,從而解決問題,但是這會降低程式的並行執行能力。

2.3 訊號(中斷處理)

  1. 比如一個鍵盤key down訊號,應該有那個執行緒處理,要不要pop-up一個新的執行緒
  2. 有多個執行緒時,如何一個執行緒修改了訊號,要不要同時通知其他執行緒
  3. 同一個訊號,不同執行緒的處理可能完全不一樣,比如ctrl+c,有些執行緒用於貼上,有些用於終止程式。

訊號的處理在單執行緒程式中就已經很複雜了,多執行緒是複雜度加倍。

2.4 堆管理

在很多系統中,當一個程式的堆疊異常時(stackoverflow),核心自動為這個程式分配堆疊,當一個程式有多個執行緒時,勢必會有多個堆疊,當核心沒有完全瞭解所有堆疊,有可能某些堆疊發生堆疊異常時,核心並不知道,無法為其自動分配堆疊。

2.5 all

如果在沒有經過大量分析和設計的前提下將多執行緒引入一個現有的單執行緒系統會產生很多不可預知的錯誤,絕不是一個簡單的引入多執行緒機制那麼簡單,要從Library等各個方面進行分析和設計,確保線上程安全的情況下再引入多執行緒。後期引入多執行緒的成本要比剛開始設計就包含多執行緒要高很多。

相關文章