1.進程標識
- 進程ID是唯一的,但也是可複用的,大部分系統採用延遲複用算法
- ID爲0的通常是調度進程,常被稱爲交換進程,是內核的一部分,不執行磁盤上的程序(所以也叫系統進程)
- 進程ID爲1的通常是init進程,自舉過程由內核調用,超級用戶特權運行,但是普通的用戶進程,不會終止
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
2、fork()函數
#include <unistd.h>
pid_t fork(void);
- 子進程返回0
- 父進程返回子進程的進程ID
- fork之後經常跟exec,所以採用了寫時複製技術
- 文件共享:
- 打開的文件描述符的複製類似於執行了dup()
- 父子進程共享同一文件偏移量
- 父子進程的區別:
- 子進程不繼承文件鎖
- 子進程未處理的鬧鐘被清除
- 子進程的未處理信號集設置爲空集
3、vfork()
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
可移植的程序不應該使用這個函數
- vfork()創建的子進程並不會完全複製父進程的地址空間,因爲會馬山調用exec
- 子進程在調用exec()前在父進程空間中運行
- vfork保證子進程先運行,子進程調用exec或exit後父進程才恢復運行
4、exit()
-
進程有5中正常終止的方法:
- main()中return
- exit()
- _[eE]xit
- 最後一個線程執行return
- 最後一個線程調用pthread_exit()
-
進程的3中異常終止狀態
- 調用abort()
- 接收到某些信號
- 最後一個線程對"取消"作出響應
-
父進程在子進程前終止,子進程編程殭屍進程
-
子進程在父進程前終止,內核爲子進程保存一定量的信息(包括進程ID,終止狀態,CPU使用時間等)
5、wait()和waitpid()
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
- 進程終止時向父進程發送SIGCHLD信號
- 調用wait時:
- 子進程還活着則阻塞
- 以終止則立即返回
- 沒有任何子進程則出錯返回
- 返回值指示退出狀態、信號編號、是否產生core文件等
WIFEXITED(status) WEXITSTATUS(status) WIFSIGNALED(status) WTERMSIG(status) WCOREDUMP(status) WIFSTOPPED(status) WSTOPSIG(status) WIFCONTINUED(status)
6、waitid()
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
- idtype
- P_PID:等待特定進程
- P_PGID:等待特定進程組中的任一子進程
- P_ALL:等待任一子進程
- options
- WCONTINUED:等待一個進程,它以前曾被停止,此後又繼續,但狀態尚未報告
- WEXITED:等待已退出的進程
- WNOHANG:非阻塞
- WNOWAIT:不破壞子進程的退出狀態
- WSTOPPED:進程已經停止,但狀態尚未報告
7、wait3()和wait4()
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
pid_t wait3(int *status, int options,
struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options,
struct rusage *rusage);
- 允許內核返回由終止進程及其所有子進程使用的資源概況
8、競爭條件
多個進程企圖對共享數據進行處理,結果取決於進程運行順序
- 爲了避免競爭條件和輪詢,進程間需要某種形式信號的發送和接收方法
9、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[]);
- 進程調用exec函數時,進程執行的程序完全替換爲新進程
- 進程ID不變,因爲只是用磁盤上的新程序替換了當前進程的正文段、數據段、堆棧
- …(暫時用不到就不看了)
10、更改用戶ID和更改組ID
int setuid(uid_t uid);
int setgid(gid_t gid);
- 在linux中,特權以及訪問控制是基於用戶ID和組ID的
- 更改用戶ID規則
- 若進程有root權限,實際/有效/保存的設置用戶ID設置爲uid
- 。。。
11、解釋器文件
- 起始行是:
#! pathname [optional-argument]
12、system()函數
int system(const char *command);
- command爲空時,可用時返回非0值
- 返回值
- -1:fork失敗或waitpid返回EINTR之外的值
- 127?:exec失敗
- shell的終止狀態:成功
13、進程會計
啓動進程會計後,每當進程結束內核就寫一個會計記錄:包括命令名、CPU時間總量、用戶ID、組ID、啓動時間內等
int acct(const char *filename);
- 該函數用以啓用和禁用進程會計,但至今沒有一個標準做了聲明,只有accton命令用了這個函數
14、用戶標識
任一進程都可以得到實際用戶ID和有效用戶ID及組ID
#include <unistd.h>
char *getlogin(void);
int getlogin_r(char *buf, size_t bufsize);
#include <stdio.h>
char *cuserid(char *string);
- 用以獲取登錄名