[APUE] 再读之进程控制
来源:互联网 发布:无痕植发的价格 知乎 编辑:程序博客网 时间:2024/05/22 13:09
本章解释了fork,exec函数族,exit,wait函数族,解释器文件,system 函数,以及进程会计和进程时间等。
1. 进程标识。
unix环境进程0为swapper调度进程,1 为init系统自举进程,2为pagedaemon,负责虚存系统。
六个函数为
pid_t getpid()pid_t getppid()uid_t getuid()uid_t geteuid()gid_t getgid()gid_t getegid()
这边比较难理解的是有效用户id和用户id.这边涉及到一个设置用户ID的概念, 说白了,设置用户ID是文件拥有者,给一张令牌,让执行本文件的人拥有文件拥有者的权限。
实例:在本文件夹下面创建文件, 文件权限,只有root用户有写权限,其他为读权限
-rw-r--r-- 1 root staff 24 9 5 20:18 record.log编写如下代码,并root用户编译后。
#include <stdio.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <sys/types.h>int main(){ FILE* fp = fopen("record.log","a+"); if (fp==NULL) { printf("error = %d, reason =%s\n", errno, strerror(errno)); return -1; } printf("uid= %d, euid=%d\n", getuid(),geteuid()); // we have the authority to open for write now fclose(fp);;}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span>
用非root用户执行的结果为:
error = 13, reason =Permission denied
给设置用户ID后:chmod +s a.out
用非root用户执行后的结果为:
uid= 501, euid=0可见设置用户ID给予提权后,uid和euid不一样了。设置组ID同理。
2. fork 函数。
fork 函数返回两次,主进程得到的是子进程的进程号,子进程得到0.
子进程会运用cow(写时复制技术) 复制父进程进程空间的。
用户ID,Session ID, 控制终端,当前工作目录,跟目录,文件屏蔽字,信号屏蔽字,环境变量,
资源限制,链接的共享存储段, 执行打开文件描述符的关闭标志(?)
子进程不复制父进程的为:
进程ID,子进程的时间信息(tms_utmie,tms_stmie,tms_cutime,tms_ustime)
父进程的锁,未决信号集。
下面一段代码为APUE作者精心设计,输出重定向到文件或者终端,打印结果不一样。一着解释了父子进程变量复制的过程。二者解释了,write 函数没有缓存,而printf行缓存的机制。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int glob =88;int main(){ pid_t pid ; int var =99; char buf[]="a write to stdout\n"; if (write(STDOUT_FILENO, buf, sizeof(buf)-1)!= sizeof(buf)-1) { printf("write to stdout error\n"); } printf("Before fork\n"); if((pid = fork())<0) { printf("fork error\n"); return -1; } else if(pid>0) //parent sleep(2); else { var++; glob++; } printf("var=%d, glob=%d,pid=%d\n",var,glob,getpid());}
下面代码需要注意的是,子进程退出时候需要用_exit(), 直接进入内核,不会刷新IO.故vfork的进程应该用_exit().
当同时不能用return, 这会修改函数栈,造成父进程crash. 如下面代码所示:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int glob =1;int main(void) { int var; var = 88; pid_t pid; if ((pid = vfork()) < 0) { printf("vfork error"); exit(-1); } else if (pid == 0) { var++; return 0; } printf("pid=%d, glob=%d, var=%d\n", getpid(), glob, var); return 0;}
4. 僵尸进程。
子进程已经死亡,而父进程并没有接收,这会造成子进程变成僵尸进程(Zombie)。如下示例中,在主进程sleep的两百秒内,子进程将变成僵尸进程。
#include <unistd.h>#include <stdlib.h>#include <stdio.h>int main(int argc,char* argv[]){pid_t pid;if ((pid= fork())<0){ printf("fork error"); exit(-1);}else if (pid>0){ printf("pid_child = %d, pid = %d\n",pid, getpid()); sleep(200);}else{ exit(0);}exit(0);}
5. wait与waitpid
wait 和waitpid 区别: 1. waitpid 可以不阻塞 2.waitpid 不像wait那样,死等第一个进程。
int waitpid(pid_t pid, int* status, int option).
pid==-1时,等待任何一个子进程
pid>0 , 等待等于PID的进程
pid==0, 等待进程组中任何一个进程
pid<-1, 等待组ID 等于pid绝对值的进程。
下面例子为pid==-1时,等待不同组中的子进程。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(){ pid_t pid; if((pid=fork())<0) { printf("fork error\n"); return -1; } else if (pid==0) //child { printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); setpgid(getpid(),getpid()); printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); sleep(5); exit(1); } else //parent { printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); setpgid(getpid(),getpid()); printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); int status; if( waitpid(-1,&status,0)==-1 ) { printf("wait pid error\n"); return -1; } else printf("child status is %d\n", WEXITSTATUS(status)); }}
下面例子为pid< -1 ,等待组ID等waitpid参数的情况
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(){ pid_t pid; if((pid=fork())<0) { printf("fork error\n"); return -1; } else if (pid==0) //child { printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); setpgid(getpid(),getpid()); printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); exit(1); } else //parent { printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); setpgid(getpid(),getpid()); printf("pid is %d, group id is %d\n", getpid(),getpgid(0)); int status; sleep(5); if( waitpid(0-pid,&status,0)==-1 ) { printf("wait pid error\n"); return -1; } else printf("child status is %d\n", WEXITSTATUS(status)); }}
6. exec 函数族
execl, execv, execle,execve,execlp,execvp.
l代表参数以list的形式传入,最后一个参数必须以(char*)0 结束。
v代表参数以数值的形式传入,数组最后一个参数也必须以(char*) 0.
e代表环境变量参数,p代表path,意思为在环境变量寻找可执行程序。
#include <stdio.h>#include <unistd.h>int main(){ pid_t pid; if((pid=fork())<0) { printf("fork error\n"); return; } else if(pid>0) { if(execl("/bin/ls","-lt","/home", (char*)0)==-1) { printf("execl error\n"); return -1; } } sleep(2); printf("*********************************************\n"); if((pid=fork())<0) { printf("fork error\n"); return; } else if(pid>0) { char* execvector[3] = {"-lt", "/home",NULL}; if(execv("/bin/ls",execvector)==-1) { printf("execl error\n"); return -1; } }}
7. setuid, seteuid, setreuid
一条规则,root用户随便改。其他用户要改的话需要程序本身拥有设置用户ID.
8. 解释器文件
!# 开头的bash 文件
9. system 函数
10. 获得用户标识
char* getlogin(void)
#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>int main(){ printf("User is %s\n", getlogin());}
11. 进程时间相关。
通过下面demo可尝试打印对应的进程以及子进程的时间信息。
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <sys/times.h>int main(int argc,char* argv[]){pid_t pid;struct tms start, end;if( times(&start)==-1){ printf("times error\n"); return -1;}if ((pid= fork())<0){ printf("fork error"); exit(-1);}else if (pid==0){ sleep(3);}else{ if((pid =wait(NULL))==-1) { printf("wait error\n"); return -1; } printf("wait pid %d\n",pid); if(times(&end)==-1) { printf("times error\n"); return -1; } long clktck=0; if((clktck=sysconf(_SC_CLK_TCK))<0) { printf("sysconf errror \n"); return -1; } printf("user: %7.2f\n",(end.tms_utime- start.tms_utime)/(double)clktck); printf("sys: %7.2f\n",(end.tms_stime- start.tms_stime)/(double)clktck); printf("child user: %7.2f\n",(end.tms_cutime- start.tms_cutime)/(double)clktck); printf("child sys: %7.2f\n",(end.tms_cstime- start.tms_cstime)/(double)clktck);}}
- [APUE] 再读之进程控制
- [APUE] 再读之进程环境
- [APUE] 再读之进程关系
- [APUE]再读之进程间通信
- [APUE] 再读之信号
- APUE读书笔记 之 进程控制
- [APUE]再读之高级IO
- [APUE]再读之 unix 基础知识
- 【APUE】笔记之——进程控制
- [APUE]再读之文件和目录
- [APUE]再读之 标准IO库
- 【APUE】进程控制
- APUE进程控制
- APUE学习:进程控制
- APUE------进程控制
- apue:进程控制
- (APUE点滴记录) 进程控制之fork与vfork
- [APUE]第八章 进程控制
- IO流与网络
- 常见的设计模式总结
- 机房收费系统 之 结账
- [LinkerScript.4] 简单的链接器脚本命令: 入口 - Simple Linker Script Commands: Entry Point
- 带参数的宏定义
- [APUE] 再读之进程控制
- 一次完整的HTTP请求所经历的7个步骤
- 二维数组中查找
- PMP杂谈--项目日历,资源日历,自然日历,资源直方图
- C++11 常量表达式
- fragment
- 模板中的参数可变
- 关键路径求解
- Android自定义控件使用attr.xml文件中的资源时在布局文件中的定义xmlns:app