第八章 进程控制

fork进程标识

id为0的是调度进程,被称为交换进程swapper,是内核的一部分

id为1的是init进程,是所以孤儿进程的父进程,不是内核一部分,只是个普通进程,但是拥有root权限,

#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);

uid_t getuid(void);//实际用户 ID
uid_t geteuid(void);//有效用户 ID

gid_t getgid(void);
gid_t getegid(void);

fork

fork后,fd会被复制到子进程,好像执行了dup函数,父子进程相同文件的fd都共享一个文件表,dup的特性

每个进程表项中fd公用相同文件表

共享当前打开文件的偏移量

fork后处理fd有两种常见操作模式

  1. 父进程等待子进程文件,防止读写相互混合
  2. 各自分工,执行不同程序段

子进程不继承父进程设置的文件锁

fork失败的两个主要原因

  1. 系统中有太多进程
  2. 该实际用户的进程总数超过了系统限制,CHILD_MAX

fork的两种方法

  1. 父进程复制自己,父子进程执行不同代码段,比如网络服务进程,父进程等待客户端请求,当有请求时父进程fork使子进程处理请求,而父进程继续等待下一个服务请求
  2. fork后执行exec,也就是spawn,当然unix是fork和exec组合就是spawn

vfork

创建一个新进程,然后exec,如同上面2

不完全拷贝父进程的地址空间,vfork保证子进程先运行

exit

大多数unix系统中,exit是标准C库中的一个函数,_exit是系统调用

_exit 和 _Exit 同义,为进程提供一种无需运行终止处理程序或信号处理程序而终止的方法,unix中并不冲洗标准IO流

exit调用_exit

5种正常终止,3种异常终止

ps 退出状态和终止状态

父进程在子进程前终止,那么子进程会被init进程(进程id是1)收养

子进程终止了,但是父进程没有获取子进程的终止状态(调用wait或者waitpid),那么这些子进程称为zombie僵死进程

wait和waitpid

#include <sys/wait.h>
pid_t wait(int *statlog);
pid_t waitpid(pid_t pid,int *statlog,int options);
//statlog 是终止状态

调用wait

  1. 子进程还在运行,则阻塞
  2. 子进程已经终止,会理解返回终止状态
  3. 没有子进程会出错返回

waitid

#include <sys/wait.h>
int waitid(idtype_t idtype,id_t id,siginfo_t *infop,int options);
/*
idtype
P_PID
P_PGID
P_ALL
*/

类似waitpid,但是根据灵活

wait3,wait4

The wait4() call provides a more general interface for programs that need to wait for certain child processes, that need resource utilization statistics accumulated by child processes, or that require options. The other wait functions are implemented using wait4().
The waitpid() call is identical to wait4() with an rusage value of zero. The older wait3() call is the same as wait4() with a pid value of -1.

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
pid_t wait3(int *statlog,int options,struct rusage *rusage);
pid_t wait4(pid_t pid,int *statlog,int options,struct rusage *rusage);

竞争条件

第十章,信号机制

第十五章和第十七章,进程间通信 IPC

exec函数

fork后,进程调用一种exec函数时,会替换为新程序

7种exec

#include <unistd.h>
int execl(const char *pathname,const char *agg0,...);
int execv(const char *pathname,char *const argv[]);
//多了envp
int execle(const char *pathname,const char *arg0,...,char *const envp[]);
int execve(const char *pathname,char *const argv[],char *const envp[]);//系统调用
//pathname变filename
int execlp(const char *filename,const char *arg0,...);
int execvp(const char *filename,char *const argv[]);
//pathname变fd
int fexecve(int fd,char *const argv[],char *const envp);


FD_CLOEXEC,进程中每个打开的fd都有一个执行时关闭标志,也就是exec后fd是否关闭的控制

系统默认是在exec后仍然保持fd的打开

POSIX.1明确要求exec时关闭目录流,opendir实现,通过调用fcntl设置了关闭标志

很多unix实现中,execve是内核的系统调用,其余6个是库函数

更改用户id和组id

#include <unistd.h>
//更改实际用户id和组id 和 有效用户id和组id
//实际+有效
int setuid(uid_t uid);
int setgid(gid_t gid);

//更改有效用户id和组id
//有效
int seteuid(uid_t uid);
int setegid(gid_t gid);

//切换实际用户id和有效用户id
int setreuid(uid_t ruid,uid_t euid);
int setregid(gid_t rgid,gid_t egid);

谁可以更改用户id(实际用户id,有效用户id,保存设置用户id),下面三点也适用与组id

  1. 进程有超级用户特权,三者都设置为uid
  2. 不是root,但是uid等于用户id或者保存设置的用户id,setuid只将有效用户id设置为uid
  3. 1和2都不满足,那么返回-1

应用场景at程序

解释器文件

system

system的实现中调用了fork,exec,waitpid,有三种返回值

  1. fork失败,-1
  2. exec失败,127

进程会计

每当进程结束时内核就写一个会计记录

一个新进程创建时会初始化,进程结束会写一个会计记录,但是init进程和守护进程不会有会计记录

每个平台实现不一

用户标志

#include <unistd.h>
char *getlogin(void);

进程调度

nice值

#include <unistd.h>
int nice(int incr);

#include <sys/resource.h>
int getpriority(int which,id_t who);
/*
which:
PRIO_PROCESS
PRIO_PGRP
PRIO_USER
*/
int setpriority(int which,id_t who,int value);

进程时间

墙上时钟时间,用户cpu时间,系统cpu时间

#include <sys/time.h>
clock_t times(struct tms *buf);//返回墙上时钟时间
struct tms { 
    clock_t tms_utime; /* user CPU time */ 
    clock_t tms_stime; /* system CPU time */ 
    clock_t tms_cutime; /* user CPU time,terminated children */ 
    clock_t tms_cstime; /* system CPU time,terminated children */ 
};
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 第七章:进程环境 7.2 main函数 main函数的原型是 当内核调用C程序时,在调用main 之前先调用一个启...
    m风满楼阅读 329评论 0 0
  • Linux 进程管理与程序开发 进程是Linux事务管理的基本单元,所有的进程均拥有自己独立的处理环境和系统资源,...
    JamesPeng阅读 2,447评论 1 14
  • 2016-02-02 进程控制 进程标识 每个进程都有一个非负整型的唯一的进程id,因为进程id表示服总是唯一的,...
    千里山南阅读 427评论 0 0
  • 1.内存的页面置换算法 (1)最佳置换算法(OPT)(理想置换算法):从主存中移出永远不再需要的页面;如无这样的...
    杰伦哎呦哎呦阅读 3,223评论 1 9
  • 鸽子蛋大小的一块石头上,我画的是《卑鄙的我》。正面画格鲁,我心中的男一号;反面的是史都华,男二号?男三号?...
    鹅湖子阅读 603评论 0 7