在代码中启动多个进程
库函数
system调用过程
system("./sleep");
系统调用
fork
- 父进程 fork()返回子进程pid
- 子进程 fork()返回0
pid_t pid;
pid = fork();
if(pid == 0){
printf("I am child,pid=%d,ppid=%d",getpid(),getppid());
}
else{
printf("I am parent,pid=%d,ppid=%d",getpid(),getppid());
sleep(1);
}
fork()实现原理
系统调用是怎么实现的
fork的性能
- 父子进程共享虚拟地址映射的物理内存,只有一方修改内容后会拷贝一份重新分配物理内存
fork()的拷贝
在逻辑上,fork()父子进程的用户态空间是拷贝的
FILE的拷贝
使用printf()尽量加上\n
内核态是拷贝还是共享的(重点)
共享文件对象,不同的文件描述符指向同一个文件对象
练习:
exec函数族
execl&execv
- 将一个可执行程序文件加载到本进程地址空间
从句子中分割得到单词strtok()
strtok(char* ,spilt” ”)
- 传入传出参数,只能使用字符数组,不能使用字面值
char sentence[] = "./add 3 4";
char* word = strtok(sentence," ");
printf("word=%s\n",word);
word = strtok(NULL," ");
printf("word=%s\n",word);
char* word = strtok(NULL," ");
printf("word=%s\n",word);
char* word = strtok(NULL," ");
printf("word=%s\n",word);
父进程回收子进程的资源
wait 同步阻塞
- 父进程等待子进程结束,回收
wait(NULL);
子进程终止的时候,父进程一直不调用wait,
- 僵尸进程
pid_t pid = fork();
if(pid==0){
printf("I am child\n");
}
else
{
printf("I am parent\n");
while(1);
}
使用wait获取子进程退出的状态
非阻塞的waitpid 同步非阻塞
- 子进程未终止,返回pid_t
- 子进程终止,回收资源
进程正常终止
进程异常终止
abort()主动异常终止
kill -6 pid
进程组
- 进程组是进程的集合,组ID是组长的PID
- 父进程和子进程属于同一组
- 组长进程终止,组ID不变,新进程PID不能和组长重复
- 普通的组员可以创建新的组长,但是组长不行
通过shell启动的进程是一个新的进程组的组长
- 在一个终端中,有至多一个前台进程组,有任意个后台进程组
会话session
- 会话是进程组的集合
会话可以连接一个终端,如果终端关闭,所有会话内进程收到一个断开连接信号
setsid()创建新会话
守护进程daemon
- 即使是会话关闭,进程依然可以持续运行
- 守护进程以d结尾 sshd
守护进程:
创建新会话,重置cwd和umask,关闭所有文件描述符
系统日志
- 它是一个文本文件
守护进程实例
进程间通信 IPC
Inter Process Communication
打破进程之间的隔离,从而进程可以共享数据
popen
- w 父进程以写的方式,写入子进程stdin
- r 父进程以读的方式,读入子进程strout
练习:实现system(“.add 3 4”);