日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

操作系统中的同步和异步

發布時間:2024/2/28 windows 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 操作系统中的同步和异步 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

操作系統中同步、異步性概念

首先我們從操作系統的發展中學習什么是異步性。在操作系統發展的初期階段,CPU處理的是作業,而且是單道批處理。什么意思呢?就是一個作業從提交到結束,程序員都不能干預,此時整臺計算機就為這一個作業服務(可想有多少資源被"浪費"),這樣有一點好處就是整個程序是"封閉的"。這樣的操作表明人和機器是沒有交互的。那我們怎么實現人機交互呢?這個答案是中斷。中斷的引入,使得工作人員能在程序運行出問題的時候也能做出相應的處理。那么在當前程序中斷后,計算機總不能讓CPU不做事吧,所以人們引入了新的概念——進程。當A進程不能繼續執行的時候(可能是因為資源不足、競爭,或是等待I/O處理),A進程會阻塞,而B進程有足夠的資源,這時操作系統便把CPU分配給B進程。當然,這里還涉及到了中斷處理程序。當A進程讓出CPU之前,中斷處理程序要做的是保護現場,即A進程的相關參數。當A進程等待的事件完成了,便可以返回中斷點重新開始工作。

簡單介紹發展史有助于我們更深刻的理解異步性的概念(當時我就是這樣一步一步把異步性、同步概念串起來的)。進程引入后,讓CPU的吞吐量得到了提升(若是單道批處理,作業等待I/O,那么這個時候CPU也要等)。但帶來的問題是程序的運行失去了封閉性異步性是指進程以不可預知的速度向前推進。在多道程序環境下,進程是并發執行的,不同進程之間存在著不同的相互制約關系(一般是資源問題)。內存中的每個進程何時執行,何時暫停,以怎樣的速度向前推進,程序總共需要多少時間才能完成等,都是不可預知的。例如,當正在執行的進程提出某種資源請求時,如打印機請求,而此時打印機正在為其他的進程打印。由于打印機是臨界資源,因此正在執行的進程必須等待,并且要放棄處理機。直到打印機空閑,并再次把處理機分配給該進程時,該進程才能繼續執行。由于資源等因素的限制,進程的執行通常都不是 一氣呵成,而是以 停停走走?的方式運行。

試想以下兩個簡單的小程序是兩個進程,其中i是公共資源。

#include<stdio.h>//程序A int i = 1; int main() {i = i + 10;//中間包含若干與i無關的操作printf("Ai = %d", i);return 0; }#include<stdio.h>//程序B int i = 1; int main() {i++;//中間包含若干與i無關的操作printf("Bi = %d", i);return 0; }

由于A和B是并發執行的,并且推進速度是不可預知的,所以最終的結果有多種情況。以下只分析兩種①:Ai = 11 Bi = 12 即:A先運行i = i + 10;并打印出來,B再運行i++。②:Ai = 12 Bi = 12 即:A先運行 i = i + 10此時并沒有打印,而B運行了i++后,A和B分別將i的值打印出來。其他情況也可以這樣分析。因為異步性的關系,我們得到的答案可能是錯誤的,或是我們不想要的。為了解決這個問題,就必須引入同步機制,使得程序能按照規則運行下去,從而得到我們想要的答案。

創建父子進程:

#include <stdio.h> #include <stdlib.h> #include <unistd.h>int main() {pid_t pid =fork();if( pid == 0 ) //子進程返回值為0{while(1){printf("This is child\n");sleep(1);}}else{while(1){printf("This is parent\n");sleep(1);}}return 0; }

可以看到,父子進程之間打印的信息并沒有固定的先后順序。當父子進程同時去訪問資源時,也不能確定獲取資源的先后順序。這就表明進程的異步性可能出現我們不想要的結果,或者說是錯誤的結果。解決上述問題的方法就是"同步"。

同步亦稱直接制約關系,它是指為完成某種任務而建立的兩個或多個進程,這些進程因為需要在某些位置上協調它們的工作次序而等待、傳遞信息所產生的制約關系。進程間的直接制約關系就是源于它們之間的相互合作。例如:上面兩個程序可以看成5+3*5中的加法程序和乘法程序。若先執行乘法程序再執行加法程序,則5+3*5=20。這個答案一定是對的嗎?其實不然。如果我們想要的答案是40,就要先執行加法程序再執行乘法程序,(5+3)*5=40。我們通過加 () 改變了運算的先后順序,使先乘除后加減變成了先加減后乘除,這就是一種同步機制。

當我們理解了異步、同步的概念后,可以簡單了解一下互斥的概念。互斥亦稱間接制約關系。當一個進程進入臨界區使用臨界資源時,另一個進程必須等待,當占用臨界資源的進程退出臨界區后,另一進程才允許去訪問此臨界資源。例如,在僅有一臺打印機的系統中,有兩個進程A和進程B,如果進程A需要打印時,系統已將打印機分配給進程B,則進程A必須阻塞。一旦進程B將打印機釋放,系統便將進程A喚醒,并將其由阻塞狀態變為就緒狀態。為禁止兩個進程同時進入臨界區,同步機制應遵循以下準則:

空閑讓進:臨界區空閑時,可以允許一個請求進入臨界區的進程立即進入臨界區。

忙則等待:當已有進程進入臨界區時,其他試圖進入臨界區的進程必須等待。

有限等待:對請求訪問的進程,應保證能在有限時間內進入臨界區。

讓權等待:當進程不能進入臨界區時,應立即釋放處理器,防止進程忙等待。

線程同步例子(使用互斥鎖):

#include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <errno.h> #include <unistd.h>/*全局變量*/ int sum = 0; /*互斥量 */ pthread_mutex_t mutex; /*聲明線程運行服務程序*/ void* pthread_function1 (void*); void* pthread_function2 (void*);int main (void) {/*線程的標識符*/pthread_t pt_1 = 0;pthread_t pt_2 = 0;int ret = 0;/*互斥初始化*/pthread_mutex_init (&mutex, NULL);/*分別創建線程1、2*/ret = pthread_create( &pt_1, //線程標識符指針NULL, //默認屬性pthread_function1, //運行函數NULL); //無參數if (ret != 0){perror ("pthread_1_create");}ret = pthread_create( &pt_2, //線程標識符指針NULL, //默認屬性pthread_function2, //運行函數NULL); //無參數if (ret != 0){perror ("pthread_2_create");}/*等待線程1、2的結束*/pthread_join (pt_1, NULL);pthread_join (pt_2, NULL);printf ("main programme exit!\n");return 0; }/*線程1的服務程序*/ void* pthread_function1 (void*a) {int i = 0;printf ("This is pthread_1!\n");for( i=0; i<3; i++ ){pthread_mutex_lock(&mutex); /*獲取互斥鎖*//*臨界資源*/sum++;printf ("Thread_1 add one to num:%d\n",sum);pthread_mutex_unlock(&mutex); /*釋放互斥鎖*//*注意,這里以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖后調用*/sleep (1);}pthread_exit ( NULL ); }/*線程2的服務程序*/ void* pthread_function2 (void*a) {int i = 0;printf ("This is pthread_2!\n");for( i=0; i<5; i++ ){pthread_mutex_lock(&mutex); /*獲取互斥鎖*//*臨界資源*/sum++;printf ("Thread_2 add one to num:%d\n",sum);pthread_mutex_unlock(&mutex); /*釋放互斥鎖*//*注意,這里以防線程的搶占,以造成一個線程在另一個線程sleep時多次訪問互斥資源,所以sleep要在得到互斥鎖后調用*/sleep (1);}pthread_exit ( NULL ); }Linux下編譯時需要加 -lpthread注意第一個字母是大寫,windows C語言中單位是毫秒(ms)。 Sleep (500); 就是到這里停半秒,然后繼續向下執行。 包含在#include <windows.h>頭文件在Linux C語言中 sleep的單位是秒(s) sleep(5);//停5秒 包含在 #include <unistd.h>頭文件

由于程序先創建的是 Thread_1,所以 Thread_1?先加鎖,即擁有使用公共資源的權限。Thread_1?在加鎖后休眠2秒,此時 Thread_2?被阻塞。若不加鎖,Thread_2 能直接對公共資源進行操作。當 Thread_1?的工作完成,它釋放互斥鎖資源,之后運行 Thread_2。同理,當 Thread_2 運行時,Thread_1?被阻塞,直至 Thread_2 完成工作并釋放互斥鎖資源。

?

?

經典進程同步問題:生產者-消費者問題

(1) 描述:一組生產者進程和一組消費者進程共享一個初始為空、大小為 n 的緩沖區,只有緩沖區沒滿時,生產者才能把消息放入到緩沖區,否則必須等待;只有緩沖區不空時,消費者才能從中取出消息,否則必須等待。由于緩沖區是臨界資源,它只允許一個生產者放入消息,或者一個消費者從中取出消息。

(2) 分析:

① 關系分析。生產者和消費者對緩沖區互斥訪問是互斥關系,同時生產者和消費者又是一個相互協作的關系,只有生產者生產之后,消費者才能消費,他們也是同步關系。

② 整理思路。這里比較簡單,只有生產者和消費者兩個進程,正好是這兩個進程存在著互斥關系和同步關系。那么需要解決的是互斥和同步 PV 操作的位置。

③ 信號量設置。信號量 mutex 作為互斥信號量,它用于控制互斥訪問緩沖池,互斥信號量初值為1;信號量 full 用于記錄當前緩沖池中

"滿"緩沖區數,初值為0。信號量 empty?用于記錄當前緩沖池中"空"緩沖區數,初值為 n。生產者-消費者進程的偽代碼如下:

semaphore mutex=1; //臨界區互斥信號量 semaphore empty=n; //空閑緩沖區 semaphore full=0; ?//緩沖區初始化為空 producer () { ?????//生產者進程while(1){produce an item in nextp; ?//生產數據P(empty); ?//獲取空緩沖區單元P(mutex); ?//進入臨界區.add nextp to buffer; ?//將數據放入緩沖區V(mutex); ?//離開臨界區,釋放互斥信號量V(full); ?//滿緩沖區數加1} }consumer () { ????//消費者進程while(1){P(full); ?//獲取滿緩沖區單元P(mutex); // 進入臨界區remove an item from buffer; ?//從緩沖區中取出數據V (mutex); ?//離開臨界區,釋放互斥信號量V (empty) ; ?//空緩沖區數加1consume the item; ?//消費數據} }

該類問題要注意對緩沖區大小為 n 的處理,當緩沖區中有空時便可對 empty 變量執行 P 操作,一旦取走一個產品便要執行 V 操作以釋放空閑區。對 empty 和 full 變量的 P 操作必須放在對 mutex 的P操作之前。如果生產者進程先執行 P(mutex),然后執行 P(empty),消費者執行 P(mutex),然后執行P(fall),這樣可不可以?答案是否定的。設想生產者進程已經將緩沖區放滿,消費者進程并沒有取產品,即empty = 0,當下次仍然是生產者進程運行時,它先執行 P(mutex) 封鎖信號量,再執行 P(empty) 時將被阻塞,希望消費者取出產品后將其喚醒。輪到消費者進程運行時,它先執行 P(mutex),然而由于生產者進程已經封鎖 mutex 信號量,消費者進程也會被阻塞,這樣一來生產者、消費者進程都將阻塞,都指望對方喚醒自己,陷入了無休止的等待。同理,如果消費者進程已經將緩沖區取空,即 full = 0,下次如果還是消費者先運行,也會出現類似的死鎖。不過生產者釋放信號量時,mutex、full 先釋放哪一個無所謂,消費者先釋放mutex 還是 empty 都可以。

總結

以上是生活随笔為你收集整理的操作系统中的同步和异步的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。