進程和程式:編寫shell——《Unix/Linux編程實踐教程》讀書筆記(第8章)

來源:互聯網
上載者:User

標籤:des   style   http   os   io   檔案   資料   for   

1、Unix shell的功能

shell是一個管理進程和運行程式的程式。所有常用的shell都有3個主要功能:

(1)運行程式;

(2)管理輸入和輸出

(3)可程式化

shell同時也是帶有變數和流程式控制制的程式設計語言。


2、Unix的進程模型

一個程式是儲存在檔案中的機器指令序列,一般它是由編譯器將原始碼編譯成二進位格式的代碼。運行一個程式意味著將這些機器指令序列載入記憶體然後讓處理器(CPU)逐條執行。在Unix術語中,一個可執行程式是一些機器指令機器資料的序列。一個進程是程式運行時的記憶體空間和設定。資料和程式儲存在磁碟檔案中,程式在進程中運行。

每個進程都有一個可以唯一標識它的數字,被稱為進程ID,一般簡稱PID;同時也有一個父進程ID(PPID)。每個進程都與一個終端相連,都一個已啟動並執行時間,有優先順序,有niceness層級,有大小。。。

Unix系統中的記憶體分為系統空間和使用者空間。進程存在於使用者空間。


3、如何執行一個程式

shell列印提示符,使用者輸入指令,shell就運行這個命令,然後shell再次列印提示符——如此反覆。

一個shell的主迴圈執行下面的4步:

(1)使用者鍵入a.out

(2)shell建立一個新的進程來運行這個出現

(3)shell將程式從磁碟載入

(4)程式在它的進程中運行知道結束

即:

while (!end_of_input)    get command    execute command    wait for command to finish


一個程式如何運行另一個程式?答案是程式通過調用exec家族函數:
man 3 exec
#include <unistd.h>extern char **environ;int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg,           ..., char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[],                char *const envp[]);/* * The exec() family of functions replaces the current process * image with a new process image. The functions described * in this manual page are front-ends for execve(2). */


4、如何建立一個進程

一個進程調用fork來複製自己。進程調用fork,當控制轉移到核心中的fork代碼後,核心做:

(1)分配新的記憶體塊和核心資料結構

(2)複製原來的進程到新的進程

(3)向運行進程添加新的進程

(4)將控制返回給兩個進程

man 2 fork
#include <unistd.h>pid_t fork(void);


5、父進程和子進程之間如何通訊(父進程如何等待子進程的退出)

進程調用wait等待子程式的結束。系統調用wait做兩件事。首先,wait暫停調用它的進程直到子進程介紹。然後,wait取得子進程結束時傳給exit的值。這樣wait執行兩個操作:通知和通訊。

wait的目的之一是通知父進程子進程結束運行了。它的第二個目的是告訴父進程子進程是如何結束的。一個進程以3中方式(成功、失敗或死亡)之一結束。按照Unix慣例,成功的程式調用exit(0)或者從main函數中return 0;程式遇到問題而要退出調用exit時傳給它一個非零的值。

父進程調用wait時傳一個整型變數地址給函數。核心將子進程的u提出狀態儲存在這個變數中。如果子進程調用exit退出,那麼核心把exit的傳回值放到這個整型變數中;如果進程是被殺死的,那麼核心將訊號序號存放在這個變數中。這個整數由3部分組成——高8位記錄退出值,低7位記錄訊號序號,第7位則用來指明發生錯誤併產生了核心映像(core dump)。

man 2 wait
#include <sys/types.h>#include <sys/wait.h>pid_t wait(int *status);pid_t waitpid(pid_t pid, int *status, int options);int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);


6、進程死亡:exit和_exit

exit是fork的逆操作,進程通過調用exit來停止運行。fork建立一個進程,exit刪除一個進程。基本上是這樣。

exit重新整理所以的流,調用atexit和on_exit註冊的函數,執行當前系統定義的其他與exit相關的操作。然後調用_exit。系統函數_exit是一個核心操作,這個操作處理所有分配給這個進程的記憶體,關閉所有這個進程開啟的檔案,釋放所有核心用來管理和維護這個進程的資料結構。

那些已經死亡但是沒有給exit賦值的進程被稱為殭屍進程。

系統調用_exit終止當前進程並執行所有必須的清理工作:

(1)關閉所有檔案描述符和目錄描述符

(2)將該進程的PID置為init進程的PID

(3)如果父進程調用wait或waitpid來等待子進程結束,則通知父進程

(4)向父進程發送SIGCHLD訊號

摘自書本,為shell的fork()、exec()和exit()迴圈

/* * prompting shell version 02 * * Solves the ‘one-shot‘ problem of version 01 * Uses execvp(), but fork()s first so that the * shell waits around to perform another command * New problem: shell cathes signals. Run vi, press ^C. */#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <string.h>#include <unistd.h>#define MAXARGS     20      /* cmdline args */#define ARGLEN      100     /* token length */int main(void){    char    *arglist[MAXARGS+1];        /* an array of ptrs */    int     numargs;                    /* index into array */    char    argbuf[ARGLEN];             /* read stuff here */    void    execute(char **);    char    *makestring(char *);          /* malloc etc */        numargs = 0;    while (numargs < MAXARGS)    {        printf("Arg[%d]?", numargs);        if (fgets(argbuf, ARGLEN, stdin) && *argbuf != ‘\n‘)            arglist[numargs++] = makestring(argbuf);        else        {            if (numargs > 0)                /* any args */            {                arglist[numargs] = NULL;    /* colse list */                execute(arglist);           /* do it */                numargs = 0;                /* and reset */            }        }    }    return 0;}void execute(char **arglist)/* * use fork and execvp and wiat to do it */{    pid_t   pid, exitstatus;                /* of child */    pid = fork();                           /* make new process */    switch (pid)    {    case -1:        perror("fork falued");        exit(1);    case 0:        execvp(arglist[0], arglist);        /* do it */        perror("execvp failed");        exit(1);    default:        while (wait(&exitstatus) != pid)            ;        printf("child exited with status %d, %d\n",            exitstatus >> 8, exitstatus & 0377);        break;    }}char *makestring(char *buf)/* * trim off newline and create storage for the string */{    char *cp;    buf[strlen(buf)-1] = ‘\0‘;              /* trim newline */    cp = malloc(strlen(buf)+1);             /* get memory */    if (cp == NULL)                         /* or die */    {        fprintf(stderr, "no memory\n");        exit(1);    }    strcpy(cp, buf);                        /* copy chars */    return cp;}


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.