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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

进程调度实验_进程运行及其调度

發布時間:2024/9/27 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 进程调度实验_进程运行及其调度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
進程概念

從空間的維度上來看,進程是一個由多種信息構成的綜合體,它包括代碼段、數據段、堆、堆棧等,圖示如下:

綜合進程關聯的各種信息而構成了的一個數據結構,我們稱為進程控制塊(Process Control Block,PCB ),也稱為任務控制塊(task control block),這些相關的信息包括:

  • 進程狀態
  • 程序計數器
  • CPU調度信息
  • 內存管理信息
  • 記賬信息
  • I/O狀態信息

從時間的維度上來看,進程是一個活動實體,表現在兩個方面:

其一,它牽連到CPU和內存,觸發CPU各種邏輯算術運算和內存中的數據活動,比如,磁盤上有一個可執行二進制文件,雙擊它時,就會衍生出來一個進程,雙擊它這一動作會觸發一系列連鎖反應,這包括程序加載到內存,通過PC逐個地引用程序指令到CPU內執行,數據在內存和寄存器之間傳輸等等。

其二,它的狀態是隨時間而變化的,且必須遵從一個原則:一次只有一個進程可在一個處理器上運行,但是許多進程可處于就緒或等待狀態。如下是一個進程狀態圖模型:

新的:進程正在創建。

就緒:進程等待分配處理器。

等待:進程等待發生某個事件(如I/O完成或收到信號)。

運行:指令正在執行。

終止:進程已經完成執行。

進程調度

多道程序是從宏觀上來看進程狀態,有2個或以上進程處于非終止運行狀態,微觀處卻只有一個進程在單處理器系統上正在運行,這就好比我們只有一雙眼睛,某一時刻只能專注于某一事物,然而,只要不閉眼,就一直在觀察事物,比如,我們在手機上看一部電視劇,看完一集的一小段,插播廣告來了,這時,我們就能去讀雜志上的一篇短文,等廣告播完了,又返回去看劇,如此往復,我們就利用拆播廣告的這段時間讀完了雜志上的一篇短文,或者,在看劇期間,我們想玩游戲了,于是,我們暫停電視劇的播放,開始玩游戲,等打完一局游戲又回去播劇看,如此往復,從總體上來看,看劇、讀雜志、玩游戲等活動像是并行的,這種“并行”的實現必須是依賴于一定的策略,包括:其一,利用電視劇間斷播放的特性;其二、設置優先級更高的活動(如玩游戲)優先執行,其三,可以控制電視劇暫停,可以對游戲進度存檔等,總體上來看,看劇、讀雜志和玩游戲這些活動都在運行而沒有結束。那么,對于操作系統而言,它把所有就緒的活動用一個隊列組織管理起來,形成就緒隊列,如下:

其中隊列頭head指向鏈表的第一個PCB塊,tail指向鏈表的最后一個PCB塊。

更進一步,建立起基于隊列圖的進程調度,其模型如下:

進程調度總是從就緒隊列里選擇一個在CPU中執行,進程在CPU中執行的活動可能是:

  • 新建了一個子進程,因為需要等待子進程執行,所以又回到就緒隊列了;
  • 發出I/O請求,并被放到I/O隊列;
  • 被中斷而需要釋放CPU;
  • 超時;
    等等~
    CPU執行活動,又反過來影響就緒隊列的結構,從而形成一種閉環機制。關于調度程序及其導致的上下文切換,限于篇幅,后續再介紹。

進程運行

進程創建形成進程樹,對于linux操作系統而言,系統初始化進程(其進程名稱可能為init,也可能為systemd,但是其ID必定是為1)是該樹形結構的根,其它所有進程都能追溯到它為止,如下,是ubuntu linux系統的一個進程樹片段:

從圖可以看出,該系統提供命令“pstree”打印系統當前的進程樹,每個新進程可以創建其他進程,并使用唯一的進程標識符(PID)來標記,同時以此來引用該進程。

關于進程創建的實現,在《Unix環境高級編程》一書中有非常詳細的介紹,這里只給出fork()系統調用實現的一個實例。

請看,該實例的編程模型如下:

????????? 對此,我們從兩個維度上來分析:

第一個維度是空間的維度,考慮子進程關聯的信息內容是什么及如何存放的問題,

  • 第一種實現是把父進程的內存全部復制,另外開辟一塊內存區域存放。
  • 第二種實現是創建父進程的堆棧、堆、數據段的完全副本,而和父進程共享正文段(因為子進程可能就是用父進程的代碼執行別的用例),再向系統申請獨立的存儲空間來存放他們。
  • 第三種實現是子進程和父進程共享全部的內容,并把這些內容標記為“只讀”,當父進程和子進程任何一個需要修改某個區域,則為修改內容向系統申請獨立的一塊內存給子進程所用,這就是“寫時復制”技術。

note:上面提及的內存都是指“物理內存”,對于linux操作系統而言,所有進程都有統一的虛擬地址空間,是不做任何區分的。

顯而易見,以上三種實現對于內存空間的使用效率最高的是第三種,“寫時復制”技術是一種高效地利用資源的方式。

第二個維度是時間的維度,考慮子進程與父進程競爭處理器的使用權問題,即它們的執行時序問題。父進程創建了子進程,直觀的想象應當是父進程先執行,盡管父進程先于子進程誕生,但是,對于選用了“寫時復制”的技術而創建進程的方式,是子進程先執行,這主要是考慮到,通常,在子進程中,會通過exec系統調用加載新的代碼段,讓子進程先執行能避免“寫時復制”拷貝共享頁面的機會,當然,父子進程誰先執行取決于系統的調度策略。???

進程終止

脫離計算機系統范疇,我們可以把一個進程認為就是一個任務,在日常事務中,終止一個任務的原因有很多,比如:

  • 任務完成了,不再需要了;
  • 由于資源欠缺,任務無法繼續;
  • 上級任務被撤銷,當前任務不再具有存在的意義;

等等~。

總之,對于計算機系統,進程是具有生命周期的,可能被終止后就不復存在了,也可能又會被復生,這里,我們考慮操作系統是如何管理進程終止問題。

操作系統提供系統調用exit()來終止進程,常規編程中,在main()函數的結束使用返回語句實際上也是調用了exit(),這里不再詳述,基于上面給出的編程模型,我們進行編碼實驗,如下:

實驗一:不使用exec系統調用,觀察父子進程對相同變量的取值

#include #include #include #include int globvar = 6; /* external variable in initialized data */char buf[] = "a write to stdout\n";intmain(void){ int var; /* automatic variable on the stack */ pid_t pid; var = 88; if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1) printf("write error"); printf("before fork\n"); /* we don't flush stdout */ if ((pid = fork()) < 0) { printf("fork error"); } else if (pid == 0) { /* child */ globvar++; /* modify variables */ var++; } else { sleep(2); /* parent */ } printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); exit(0);}

構建并執行程序

glob代表數據段,var代表堆棧段,在父子進程中,它們的值不相同,這說明,父子進程實際訪問的物理內存單元不一樣,盡管他們通過同一個變量引用(也就是說使用了相同的虛擬地址),當然,父子進程至少共用了同一段代碼即第30行代碼。

實驗二:使用exec系統調用,觀察進程從創建到終止的過程#include #include #include int main(){pid_t pid; /* fork a child process */ pid = fork(); if (pid < 0) { /* error occurred */ fprintf(stderr, "Fork Failed\n"); return 1; } else if (pid == 0) { /* child process */ printf("I am the child %d\n",pid); execlp("/bin/ls","ls",NULL); } else { /* parent process */ /* parent will wait for the child to complete */ printf("I am the parent %d\n",pid);????wait(NULL); printf("Child Complete\n");??} return 0;}

構建并執行程序

對照上面所述的編程模型,代碼行22先執行,然后執行代碼行17,fork()系統調用返回值為0標記在子進程空間,大于0標記在父進程空間,fork()之初,在子進程空間的代碼是完全和父進程相同,之后,在父進程空間中,使用wait()系統調用控制自己的狀態進入等待子進程終止信號,父進程讓出處理器,在子進程空間中,使用execlp()加載并執行程序ls,子進程一旦終止,就會觸發父進程回到運行狀態,從而執行代碼行24。

總結

以上是生活随笔為你收集整理的进程调度实验_进程运行及其调度的全部內容,希望文章能夠幫你解決所遇到的問題。

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