進程共同實現某個任務或者共享計算機資源, 它們之間存在兩種關系:
1.同步關系, 指為了完成任務的進程之間, 因為需要在某些位置協調它們的執行順序而等待, 傳遞消息產生的制約關系.
2.互斥關系, 進程間因相互競爭使用獨占型資源所產生的制約關系, 如一個進程使用打印機,另一個進程必須等待它使用完后才可使用.
臨界資源: 一次僅允許一個進程使(必須互斥使用)的資源, 如獨占型硬件資源.....
臨界段: 指各進程必須互斥執行的程序段, 該程序段實施對臨界資源的操作.
關鍵區對象為:CRITICAL_SECTION 當某個線程進入關鍵區之后,其他線程將阻塞等待,直到該線程釋放關鍵區的擁有權.
#include <windows.h> #include <stdio.h> static int number=10; CRITICAL_SECTION CriticalSection; DWORD WINAPI ThreadOne(LPVOID lpParameter) { printf("窗口1售票開始:\n"); while(1) { EnterCriticalSection(&CriticalSection); if(number>0) { printf("窗口1售出第%d張票...\n",number); number--; Sleep(1000); } LeaveCriticalSection(&CriticalSection); Sleep(100); } return 0; } DWORD WINAPI ThreadTwo(LPVOID lpParameter) { printf("窗口2售票開始:\n"); while(1) { EnterCriticalSection(&CriticalSection); if(number>0) { printf("窗口2售出第%d張票...\n",number); Sleep(1000); number--; } LeaveCriticalSection(&CriticalSection); Sleep(100); } return 0; } int main() { HANDLE HOne,HTwo; InitializeCriticalSection(&CriticalSection); printf("***********************vpoet******************\n"); HOne=CreateThread(NULL,0,ThreadOne,NULL,0,NULL); HTwo=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL); CloseHandle(HOne); CloseHandle(HTwo); while(TRUE) { if(number==0) { printf("不好意思,票賣完了!\n"); DeleteCriticalSection(&CriticalSection); return 0; } else { continue; } } return 0; }
信號量機制: 由信號量和P操作,V操作兩部分組成, 可以解決互斥與同步問題. 信號量(s)為一個整型變量, 只能被兩個標准原語訪問, 分別記為P操作和V操作.
定義如下:
P(s){ while s <= 0 ; //空操作 s = s - 1; } V(s){ s =s + 1; }
信號量可以解決n個進程的臨界段問題, n個進程共享一個公共變量mutex, 其初值為 1 , 任意一個進程Pi的結果如下:
do{ P(mutex); critical secition V(mutex); non critical secition }while(1);
信號量也可以解決進程間同步問題.
利用信號量解決線程同步問題
#include <windows.h> #include <stdio.h> static int number=10; HANDLE Sem; DWORD WINAPI ThreadOne(LPVOID lpParameter) { printf("窗口1售票開始:\n"); while(1) { // 信號量 > 0, 減去 1 WaitForSingleObject(Sem,INFINITE); if(number>0) { printf("窗口1售出第%d張票...\n",number); number--; Sleep(1000); } // 信號量 < 0 , 加上 1 ReleaseSemaphore(Sem,1,NULL); Sleep(100); } return 0; } DWORD WINAPI ThreadTwo(LPVOID lpParameter) { printf("窗口2售票開始:\n"); while(1) { WaitForSingleObject(Sem,INFINITE); if(number>0) { printf("窗口2售出第%d張票...\n",number); Sleep(1000); number--; } ReleaseSemaphore(Sem,1,NULL); Sleep(100); } return 0; } int main() { HANDLE HOne,HTwo; printf("***********************vpoet******************\n"); HOne=CreateThread(NULL,0,ThreadOne,NULL,0,NULL); HTwo=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL); //創建信號量, 初始為 1 , 最大計數為 1 Sem=CreateSemaphore(NULL,1,1,NULL); CloseHandle(HOne); CloseHandle(HTwo); while(TRUE) { if(number==0) { printf("不好意思,票賣完了!\n"); CloseHandle(Sem); return 0; } else { continue; } } return 0; }
信號量的具體實現:與進程調度相結合, 消除忙等待現象.
基本思想:
在P操作循環等待的地方介入放棄處理機, 進入等待對了動作.
在V操作時, 從等待隊列中摘取進程變為就緒.
信號量定義
typedef struct{ int:value; 一個數值型變量 struct process *L;一個PCB隊列 } Semaphore Semaphore S;
P操作
P(S): S.Value=S.value-1; if S.value<0 then 保存現場, 將本進程掛入S.L隊列,等待重新調度
請求分配一個S代表的資源, 若S.value < 0, 代表系統無此資源, 申請者阻塞.
V操作
V(S): S.value:=value+1 if S.value≤0 then 從S.L隊列 取一進程,掛入就緒隊列。
進程釋放一個S代表的資源, 若S.value <= 0, 表示尚有進程在等待S而被阻塞, 所有要喚醒其一.
管程
共享資源用共享數據結構表示, 把分散的對共享資源的臨界段集中於管程中, 管程中的臨界程序一次只允許一個進程調用.
主要構成:共享數據結構, 對共享數據結構操作的一組函數, 數據結構的初始化程序.
互斥對象實現線程同步
互斥對象的所有權輪換給兩個線程
#include <windows.h> #include <stdio.h> static int number=10; HANDLE Mutex; DWORD WINAPI ThreadOne(LPVOID lpParameter) { while(1) { //等待互斥對象有多有權才返回 WaitForSingleObject(Mutex,INFINITE); if(number>0) { printf("窗口1售出第%d張票...\n",number); number--; Sleep(1000); } //釋放互斥對象所有權 ReleaseMutex(Mutex); } return 0; } DWORD WINAPI ThreadTwo(LPVOID lpParameter) { while(1) { WaitForSingleObject(Mutex,INFINITE); if(number>0) { printf("窗口2售出第%d張票...\n",number); Sleep(1000); number--; } ReleaseMutex(Mutex); } return 0; } int main() { HANDLE HOne,HTwo; Mutex=CreateMutex(NULL,FALSE,NULL); printf("***********************vpoet******************\n"); HOne=CreateThread(NULL,0,ThreadOne,NULL,0,NULL); printf("窗口1售票開始:\n"); HTwo=CreateThread(NULL,0,ThreadTwo,NULL,0,NULL); printf("窗口2售票開始:\n"); CloseHandle(HOne); CloseHandle(HTwo); while(TRUE) { if(number==0) { printf("不好意思,票賣完了!\n"); CloseHandle(Mutex); return 0; } else { continue; } } return 0; }
