標籤:style blog http color os 使用 ar strong for
簡介
進程同步是一個作業系統層級的概念,是在多道程式的環境下,存在著不同的制約關係,為了協調這種互相制約的關係,實現資源共用和進程協作,從而避免進程之間的衝突,引入了進程同步。
臨界資源
在作業系統中,進程是佔有資源的最小單位(線程可以訪問其所在進程內的所有資源,但線程本身並不佔有資源或僅僅佔有一點必須資源)。但對於某些資源來說,其在同一時間只能被一個進程所佔用。這些一次只能被一個進程所佔用的資源就是所謂的臨界資源。典型的臨界資源比如物理上的印表機,或是存在硬碟或記憶體中被多個進程所共用的一些變數和資料等(如果這類資源不被看成臨界資源加以保護,那麼很有可能造成丟資料的問題)。
對於臨界資源的訪問,必須是互訴進行。也就是當臨界資源被佔用時,另一個申請臨界資源的進程會被阻塞,直到其所申請的臨界資源被釋放。而進程內訪問臨界資源的代碼被成為臨界區。
對於臨界區的訪問過程分為四個部分:
1.進入區:查看臨界區是否可訪問,如果可以訪問,則轉到步驟二,否則進程會被阻塞
2.臨界區:在臨界區做操作
3.退出區:清除臨界區被佔用的標誌
4.剩餘區:進程與臨界區不相關部分的代碼
進程間同步和互訴的概念
進程同步
進程同步也是進程之間直接的制約關係,是為完成某種任務而建立的兩個或多個線程,這個線程需要在某些位置上協調他們的工作次序而等待、傳遞資訊所產生的制約關係。進程間的直接制約關係來源於他們之間的合作。
比如說進程A需要從緩衝區讀取進程B產生的資訊,當緩衝區為空白時,進程B因為讀取不到資訊而被阻塞。而當進程A產生資訊放入緩衝區時,進程B才會被喚醒。概念1所示。
圖1.進程之間的同步
用C#代碼類比進程之間的同步如代碼1所示。
class ProcessSyn { private static Mutex mut = new Mutex(); static void Main() { Console.WriteLine("進程1執行完了進程2才能執行......."); Thread Thread1 = new Thread(new ThreadStart(Proc1)); Thread Thread2 = new Thread(new ThreadStart(Proc2)); Thread1.Start(); Thread2.Start(); Console.ReadKey(); } private static void Proc1() { mut.WaitOne(); Console.WriteLine("線程1執行操作...."); Thread.Sleep(3000); mut.ReleaseMutex();//V操作 } private static void Proc2() { mut.WaitOne();//P操作 Console.WriteLine("線程2執行操作...."); mut.WaitOne(); } }
代碼1.C#類比進程之間的同步
運行結果2所示。
圖2.運行結果
進程互斥
進程互斥是進程之間的間接制約關係。當一個進程進入臨界區使用臨界資源時,另一個進程必須等待。只有當使用臨界資源的進程退出臨界區後,這個進程才會解除阻塞狀態。
比如進程B需要訪問印表機,但此時進程A佔有了印表機,進程B會被阻塞,直到進程A釋放了印表機資源,進程B才可以繼續執行。概念3所示。
圖3.進程之間的互斥
用C#類比進程之間的互斥,這裡我啟動了5個線程,但同一時間內只有一個線程能對臨界資源進行訪問。如代碼2所示。
class ProcessMutex { private static Mutex mut = new Mutex(); private const int numThreads = 5; static void Main() { for (int i = 0; i <= numThreads; i++) { Thread myThread = new Thread(new ThreadStart(UseResource)); myThread.Name = String.Format("線程{0}", i + 1); myThread.Start(); } Console.ReadKey(); } //同步 private static void UseResource() { // 相當於P操作 mut.WaitOne(); /*下面代碼是線程真正的工作*/ Console.WriteLine("{0}已經進入臨界區", Thread.CurrentThread.Name); Random r = new Random(); int rNum = r.Next(2000); Console.WriteLine("{0}執行操作,執行時間為{1}ms", Thread.CurrentThread.Name,rNum); Thread.Sleep(rNum); Console.WriteLine("{0}已經離開臨界區\r\n", Thread.CurrentThread.Name); /*線程工作結束*/ // 相當於V操作 mut.ReleaseMutex(); } //互斥 }
代碼2.C#類比進程之間的互斥
運行結果4所示。
圖4.C#類比進程互斥
實現臨界區互斥的基本方法
硬體實現方法
通過硬體實現臨界區最簡單的辦法就是關CPU的中斷。從電腦原理我們知道,CPU進行進程切換是需要通過中斷來進行。如果屏蔽了中斷那麼就可以保證當前進程順利的將臨界區代碼執行完,從而實現了互斥。這個辦法的步驟就是:屏蔽中斷--執行臨界區--開中斷。但這樣做並不好,這大大限制了處理器交替執行任務的能力。並且將關中斷的許可權交給使用者代碼,那麼如果使用者代碼屏蔽了中斷後不再開,那系統豈不是跪了?
還有硬體的指令實現方式,這個方式和接下來要說的訊號量方式如出一轍。但是通過硬體來實現,這裡就不細說了。
訊號量實現方式
這也是我們比較熟悉P V操作。通過設定一個表示資源個數的訊號量S,通過對訊號量S的P和V操作來實現進程的的互斥。
P和V操作分別來自荷蘭語Passeren和Vrijgeven,分別表示佔有和釋放。P V操作是作業系統的原語,意味著具有原子性。
P操作首先減少訊號量,表示有一個進程將佔用或等待資源,然後檢測S是否小於0,如果小於0則阻塞,如果大於0則佔有資源進行執行。
V操作是和P操作相反的操作,首先增加訊號量,表示佔用或等待資源的進程減少了1個。然後檢測S是否小於0,如果小於0則喚醒等待使用S資源的其它進程。
前面我們C#類比進程的同步和互斥其實算是訊號量進行實現的。
作業系統--進程同步和互斥的概念