標籤: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;}