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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux C : 进程管理实验:创建进程、上下文切换

發布時間:2024/10/14 linux 84 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux C : 进程管理实验:创建进程、上下文切换 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ?進程可以看成程序的執行過程,可以展示在當前時刻的執行狀態。它是程序在一個數據集合上的一次動態執行的過程。這個數據集合通常包含存放可執行代碼的代碼段,存放初始化全局變量和初始化靜態局部變量的數據段、用于調試的符號表、未初始化的全局變量和未初始化的靜態局部變量的bss段,存放對象數據和臨時變量以及數據層次結構的堆棧,系統資源等
? ? ? ?進程有多種狀態,例如創建,就緒,執行,等待,終止 等。

? ? ? ?為了實驗簡單,暫時只設置如下的進程狀態:空閑狀態,就緒,睡眠,僵尸狀態。其中,僵尸狀態值的是進程已經執行結束,但是還沒釋放資源的進程。而對于單CPU的系統來說,獲得CPU使用權的進程狀態就是執行態,進程執行結束就應該釋放資源。

目錄

一、結構體定義

二、上下文切換

三、優先級隊列

四、進程操作

五、編譯和執行


一、結構體定義

在 type.h中 定義進程的結構體:

為了盡量和實際操作系統中保持一致,要把棧?kstack 放在結構體的最后面,棧底到棧頂,就是從高地址到低地址,從kstack[SSIZE -1 ] 到 kstack [0] 。而saved_sp就是這個棧的棧頂指針。

// // Created by Administrator on 2021/6/7. //#ifndef PROCESSMANAGEMENT_TYPE_H #define PROCESSMANAGEMENT_TYPE_H#define NPROC 9 #define SSIZE 1024 #define proc PROCenum ProcStatus{FREE=0,READY,SLEEP};typedef struct Process{struct Process * next; //同優先級的下一個同狀態進程int *saved_sp ; //棧頂指針int pid; //idint ppid; //父進程int status; //狀態 Free|ready| etcint priority; //優先級int event ; //造成睡眠的事件idint exitCode ; //進程退出值struct Process *child; //first child PROC pointerstruct Process *slbling; //兄弟節點struct Process *perent; //父節點int kstack[SSIZE]; //棧空間}PROC;#endif //PROCESSMANAGEMENT_TYPE_H

二、上下文切換

? ? ? ?上下文切換,指的是正在執行的進程因為某些原因需要讓出CPU使用權,需要保留現有的狀態,等到重新獲得CPU使用權的時候,恢復剛剛暫停執行時的狀態繼續執行。scheduler 方法在后續中會講到,它的功能是把當前執行的進程running弄到就緒隊列中,再從就緒隊列中搞一個進程來執行。

? ? ? ?在tswitch.s 匯編文件中寫入下述代碼。其中?

? ? ? ? ? movl ? running,%ebx? ??
? ? ? ? ? movl ? %esp,4(%ebx)

? ? ? 這段代碼把 running指針的值放入%ebx,而 4(%ebx)則是running地址再往高地址偏移4個字節,對應再程序中的變量是?Process 中的 *saved_sp變量。所以這兩句代碼就是為了?saved_sp= %esp

? ? ? 當running換成新進程后,再 Resume 代碼塊,先 %esp = saved_sp,然后再按順序出棧,把之前的狀態進行恢復。執行到ret時,彈出PC寄存器的代碼地址繼續執行。

.globl running,scheduler,tswitch tswitch: SAVE: # on entry: stack top = retPCpushl %eax # save CPU registers on stackpushl %ebxpushl %ecxpushl %edxpushl %ebppushl %esipushl %edipushflmovl running,%ebx # ebx -> running PROCmovl %esp,4(%ebx) # running PROC.saved_sp = espFIND: call scheduler # pick a new running PROCRESUME: movl running,%ebx # ebx -> (new) running PROCmovl 4(%ebx),%esp # esp = (new) running PROC.saved_sppopfl # restore saved registers from stackpopl %edipopl %esipopl %ebppopl %edxpopl %ecxpopl %ebxpopl %eaxret # return by retPC on top of stack # stack contents = |retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag| # -1 -2 -3 -4 -5 -6 -7 -8 -9

三、優先級隊列

? ? ? 隊列采用鏈表形式進行組織,對進程列表按照優先級進行入隊、出隊、打印操作

#include "queue.h"/*** <p> 把進程指針P 放進優先級指針數組中* @param queue* @param p* @return*/ static int enqueue(PROC **queue ,PROC * p){PROC *q = *queue;if (q==NULL || p->priority > q->priority){//如果隊列為空或者P的優先級要比隊列頭來得高,那么直接放進隊列頭*queue = p;p->next = q;}else{//否則定位到對應的優先級序列while(q->next!=NULL && p->priority <= q->next->priority){q = q->next;}p->next = q->next;q->next = p;} }static PROC* dequeue(PROC ** queue){PROC *p= *queue;if(p!=NULL){*queue = (*queue)->next;}return p; }static int printList (const char * name ,PROC * p){printf("%s =",name);while(p){printf("[%d %d ]->",p->pid,p->priority);p=p->next;}printf("NULL\n");return 0; }

四、進程操作

1)定義執行、空閑、就緒、睡眠狀態進程隊列 ,本次示例最多有 NPROC=9 個進程?

2)CPU使用權切換 scheduler,把一個正在執行的換進就緒隊列中,再從就緒隊列換出一個進程。

3)上下文切換 do_switch, 其中,tswitch的定義在?tswitch.s文件中。該方法實現,保存寄存器狀態值,恢復一個就緒態的進程,并恢復該進程暫停之前的狀態

4)創建進程 do_kfork ,從空閑隊列中抽出一個進程并初始化信息,加入到就緒隊列中。

在初始化過程中,kstack[SSIZE-1] 賦成和 body的函數地址,save_sp指針指向kstack[SSIZE -9]。意味著,如果在tswtich.s 執行?movl .save_sp ,%esp 后再pop??8個寄存器后,esp寄存器對應的內存單元就是kstack[SSIZE-1] 即body的函數地址,再ret一下,就會執行body函數。

5)進程退出 do_exit , 把進程重新加入到空閑隊列中。

6)系統初始化? init ,假設在該系統中 proc [0]? 即 P0 的進程優先級最低,在空閑列表中的進程都是P0進程的子進程?,子進程的優先級都為1 ,P0進程的優先級為0。

7) main 函數:初始化進程P0,并創建一個子進程。調用tswitch 切換到子進程中,如果子進程都結束退出,那么P0才有機會重新獲取CPU執行權。P0結束,程序結束?

#include <stdio.h> #include "type.h"int kfork(), kexit(), tswitch(), printList(), enqueue() ;PROC proc[NPROC], *running, *freeList, *readyQueue, *sleepList;int do_switch() {printf("proc %d switching task\n", running->pid);tswitch();printf("proc %d resuming\n", running->pid); }int do_kfork() {int child = kfork();if (child < 0)printf("kfork failed\n");else{printf("proc %d kforked a child = %d\n", running->pid, child); printList("readyQueue", readyQueue);}return child; }int kexit(){running->status = FREE;running->priority = 0;// ASSIGNMENT 3: add YOUR CODE to delete running PROC from parent's child listenqueue(&freeList, running); // enter running into freeListprintList("freeList", freeList); // show freeListtswitch(); }int do_exit() {if (running->pid==1){printf("P1 never dies\n");return -1;}kexit(); // journey of no return }int body() {int c, CR;printf("proc %d starts from body()\n", running->pid);while(1){printf("***************************************\n");printf("proc %d running: Parent = %d\n", running->pid, running->ppid);// ASSIGNMENT 3: add YOUR CODE to show child listprintf("input a char [f|s|q] : ");c = getchar(); CR=getchar(); switch(c){case 'f': do_kfork(); break;case 's': do_switch(); break;case 'q': do_exit(); break;}} }/*******************************************************kfork() creates a child porc; returns child pid.When scheduled to run, child PROC resumes to body(); ********************************************************/ int kfork() {PROC *p;int i;/*** get a proc from freeList for child proc: ***/p = dequeue(&freeList);if (!p){printf("no more proc\n");return(-1);}/* initialize the new proc and its stack */p->status = READY;p->priority = 1; // for ALL PROCs except P0p->ppid = running->pid;// -1 -2 -3 -4 -5 -6 -7 -8 -9// kstack contains: |retPC|eax|ebx|ecx|edx|ebp|esi|edi|eflag|for (i=1; i<10; i++)p->kstack[SSIZE - i] = 0;p->kstack[SSIZE-1] = (int)body;p->saved_sp = &(p->kstack[SSIZE - 9]); /**************** ASSIGNMENT 3 ********************add YOUR code to implement the PROC tree as a BINARY treeenter_child(running, p); ****************************************************/enqueue(&readyQueue, p);return p->pid; }int init() {int i;for (i = 0; i < NPROC; i++){proc[i].pid = i; proc[i].status = FREE;proc[i].priority = 0;proc[i].next = (PROC *)&proc[(i+1)];}proc[NPROC-1].next = 0;freeList = &proc[0]; readyQueue = 0;sleepList = 0;// create P0 as the initial running processrunning = dequeue(&freeList);running->status = READY;running->priority = 0; running->child = 0; running->sibling = 0; running->parent = running;printf("init complete: P0 running\n"); printList("freeList", freeList); }/*************** main() ***************/ int main() {printf("\nWelcome to 360 Multitasking System\n");init();kfork(); printf("P0: switch task\n");tswitch();printf("All dead. Happy ending\n"); }/*********** scheduler *************/ int scheduler() { printf("proc %d in scheduler()\n", running->pid);if (running->status == READY)enqueue(&readyQueue, running);printList("readyQueue", readyQueue);running = dequeue(&readyQueue);printf("next running = %d\n", running->pid); }

五、編譯和執行

編譯上述文件:命令為

gcc -m32? t.c? tswtich.s queue.c?

再執行 ./a.out 如下結果:

參考書本《Systems Programming in Unix/Linux》 或 譯文《Unix/Linux 系統編程》

總結

以上是生活随笔為你收集整理的Linux C : 进程管理实验:创建进程、上下文切换的全部內容,希望文章能夠幫你解決所遇到的問題。

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