笔记二:进程间的通信(fork、孤儿进程,僵死进程等)
来源:互联网 发布:淘宝模板怎么用 编辑:程序博客网 时间:2024/06/10 14:47
以下是以前学习《unix环境高级编程》时的一些笔记和测试代码,好久没看过了,没有再次验证,存在错误的话,希望见谅,分享下主要是!!!
ps 查看系统中的进程 ps–axj
A与B在用户空间是不能通信的,相当于封闭的房子,也没有窗户,所以在用户空间是无法通信的
二:进程控制相关函数
1.fork()函数
功能:创建一个子进程
参数:没有参数
返回值:成功,返回二个值;0 --- 子进程中 >0(子进程的PID号) ---- 父进程中
出错,返回一个值-1
成功时,内核为何会返还二个值?
用户空间的进程,可以认为是一个封闭的房子(在用户空间),内核是怎样对用户空间这么多进程进行管理,怎样识别,是通过PID。
fork() 调用成功,内核则在用户空间创建一个进程(房子),这个房子和之前的进程代码段,数据段等都一样(除了PID之外)
以下两段fork函数简单的使用
以下两段fork函数简单的使用
#include "stdio.h"#include "unistd.h"#include "sys/types.h"#include "stdlib.h"int main(){ pid_t pid; pid=fork(); printf("hello linux\n"); usleep(200); //200微秒 printf("11111111111\n"); while(1); return 0;}
#include "stdio.h"#include "unistd.h"#include "sys/types.h"#include "stdlib.h"int main(){ pid_t pid; pid=fork(); if(pid >0) { printf("parent process run\n"); } if(pid ==0) { printf("child process run\n"); } while(1); return 0;}
getpid(); 获取本进程的PID号(返回值)
getppid();获取本进程父进程PID号(返回值)
exit(): 进程退出函数
什么是僵尸进程?什么是孤儿进程?
什么是僵尸进程?什么是孤儿进程?
子进程退出,父进程没有退出,此时子进程处于Z(zobile)(僵尸) 状态,处于此状态的进程仍要耗费系统资源。子进程自己不能回收资源,只有父亲负责为子进程回收资源。父进程退出,子进程没有退出,此时子进程变为孤儿进程,会被1号进程收养,即init进程为其父进程。
例子1:
/*僵尸进程 查看进程pid状态等消息 可以终端使用命令ps aux或者ps axj*/#include "signal.h"#include "sys/types.h"#include "stdio.h"int main(){ pid_t pid; pid = fork(); if(pid < 0) { printf("创建进程失败\n"); return -1; } /*对于父进程首先是睡眠(8秒)S状态,8秒后进入R(运行)状态 对于子进程就变成了T状态; */ if(pid > 0) { sleep(8);//睡眠状态; /*如果设置的waitpid设置为waitpid(pid,NULL,0)为阻塞,那么将不会产生僵尸进程,父进程会为其回收*/ if(waitpid(pid,NULL,WNOHANG) == 0)//等待子进程结束;可以设置为非阻塞(WNOHANG); { kill(pid,9);//杀死子进程,父进程没有结束,子进程将变成Z状态,因为父进程没有给子进程回收资源,子进程将变为僵尸进程; } while(1); } if(pid == 0) { printf("raise function before\n"); raise(SIGTSTP);//暂停程序,相当于ctrl+z; T状态 printf("raise function after\n"); exit(0); }}
如果我们要求:子进程退出,父进程没有退出,同时也不要子进程处于Z(zobile) 状态,而是完全结束,怎么办?
2.exit()--------库函数 进程的退出函数
头文件:#include “stdlib.h”
参数: int 退出状态----- 假设:0 为正常退出,-1为非正常退出
exit中的参数退出状态主要作用是传递给父进程,父进程根据这些状态可判定子进程现在处于什么情况。父进程怎样接收到这个状态呢?是通过wait 或waitpid
exit()------系统调用函数----unistd.h
以下为exit()和_exit()基本使用
以下为exit()和_exit()基本使用
#include "stdio.h"#include "unistd.h"#include "stdlib.h"int main(){ printf("hello linux"); // fflush(stdout); //_exit(0); exit(0); printf("1111111111111"); return 0;}
3 wait()函数
所需头文件:#include <sys/types.h>
#include <sys/wait.h>
函数原型: pid_t wait(int *status)
函数参数: status 是一个整型指针,指向的对象用来保存子进程退出时的状态。
status 若为空,表示忽略子进程退出时的状态
status 若不为空,表示保存子进程退出时的状态
另外,子进程的结束状态可由Linux中一些特定的宏来测定。
函数返回值: 成功:子进程的进程号 失败:-1
什么时候会阻塞,什么时候不会阻塞?
调用该函数使进程阻塞(睡眠),直到任一个子进程结束或者是该进程接收到了一个信号为止。
如果该进程没有子进程或者其子进程已经结束,wait函数会立即返回,即不会阻塞。
以下是关于wait函数的使用
以下是关于wait函数的使用
#include "sys/wait.h"#include "sys/types.h"#include "stdio.h"int main(){ printf("wait before\n"); wait(NULL); printf("wait after\n"); return 0;}
#include "sys/types.h"#include "stdio.h"#include "unistd.h"int main(){ pid_t pid; pid=fork(); if(pid <0 ) { printf("creat process failure\n"); return -1; } if(pid ==0)//child process { printf("this is child process\n") ; while(1); } if(pid >0) //parent process { printf("this is parent process\n"); printf("parent process:wait before\n"); wait(NULL); printf("parent process:wait after\n"); while(1); } return 0;}解析:
子进程1:
printf ------- pid
sleep(10) -------S 10秒后 结束
exit(1)
子进程2:
printf ------- pid
sleep(20) -------S S(睡眠状态) 再过10秒
exit(3)
父进程:
printf---
printf ---wait before
pet=wait------------------S
printf---wait after ret=%d
pet=wait S(睡眠状态) R(运行状态)
printf second wait ret=%d
#include "sys/types.h"#include "sys/wait.h"#include "unistd.h"#include "stdio.h"#include "stdlib.h"int main(){ pid_t pid; int ret; pid = fork(); if(pid <0) { printf("creat process failure\n"); return -1; } if(pid == 0) //child process1 { printf("this is a child process,pid=%d\n",getpid()); sleep(10); exit(1); } if(pid >0) { pid_t pid1; pid1=fork(); if(pid1<0) { printf("creat child process1 failure\n"); exit(2); } if(pid1 ==0) { printf("this is a child process1 run,pid=%d\n",getpid()); sleep(20); exit(3); } printf("this is a parent process\n"); printf("wait before\n"); ret=wait(NULL); printf("wait after,first wait ret=%d\n",ret); ret=wait(NULL); printf("second wait after,ret=%d\n",ret); while(1); return 0; }
4. waitpid() 功能比wait 功能更强
可以等待某一个子进程退出,可通过第一个参数来实现
所需头文件:#include <sys/types.h>
#include <sys/wait.h>
函数原型: pid_t waitpid(pid_t pid, int *status, int options)
函数参数: pid pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1:等待任何一个子进程退出,此时和wait作用一样。
pid=0:等待其组ID等于调用进程的组ID的任一子进程。
pid<-1:等待其组ID等于pid的绝对值的任一子进程。
status 同wait
options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0
WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
0:同wait,阻塞父进程,等待子进程退出。
函数返回值: 正常:结束的子进程的进程号
使用选项WNOHANG且没有子进程结束时:0
调用出错:-1
例子:
例子:
#include "sys/types.h"#include "sys/wait.h"#include "unistd.h"#include "stdio.h"#include "stdlib.h"int main(){ pid_t pid; int ret; int status; pid = fork(); if(pid <0) { printf("creat process failure\n"); return -1; } if(pid == 0) //child process1 { printf("this is a child process,pid=%d\n",getpid()); sleep(10); exit(1); } if(pid >0) { pid_t pid1; pid1=fork(); if(pid1<0) { printf("creat child process1 failure\n"); exit(2); } if(pid1 ==0) { printf("this is a child process1 run,pid=%d\n",getpid()); sleep(20); exit(3); } printf("this is a parent process\n"); printf("wait before\n"); ret=waitpid(pid1,&status,0); printf("wait after,first wait ret=%d,status=%d\n",ret,WEXITSTATUS(status));// ret=wait(&status);// printf("second wait after,ret=%d,status=%d\n",ret,WEXITSTATUS(status)); while(1); return 0; }}
5 vfork() ----形式和fork()
vfork() 调用成功,内核则在用户空间创建一个进程,但是不会重新建立一个房子,父子里程共享父进程这个房子,然后子进程先运行,父进程后运行
6.在此之前创建子进程,子进程进行了代码的完全拷贝,虽然我们用返回值的不同使得父子进程执行了二个不同的代码区。但是很多情况下:
父子进程的代码完全不一样,比如 bash 这是父进程,a.out 是子进程,这二段代码没有相似性;或父进程是C代码,子进程是一个shell脚本,等,我们应该怎么处理?
当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的程序,我们应该怎么处理?
伪代码:
伪代码:
int main() computer 这个可执行程
{
printf(“dfdfggf\n”);
i++;
.....
Computer//不是函数,而是另外一个程序
}
可以通过exec 函数族来解决这些问题。
函数的功能:可以调用另外一个程序来运行,会把原来的程序中的代码段,数据段等都替换掉,从这个调用的程序的开始来执行,会保留原进程的PID,其它都不保留。
什么时候要用这个函数呢?
当进程认为自己不能再为系统和用户做出任何贡献了时就可以调用exec函数,让自己执行新的任务。
如果某个进程想同时执行另一个程序,它就可以调用fork函数创建子进程,然后在子进程中调用任何一个exec函数。这样看起来就好像通过执行应用程序而产生了一个新进程一样。
所需头文件:#include <unistd.h>
函数原型: int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]:xp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);//环境变量加
函数返回值: -1:出错,成功是0
参数: 第一个参数,前面四个都一样,后面二个一样,path file
path 必须要指定所在程序的路径,要不是绝对路径或相对路径
file 不用指定路径(指定路径也可以),在环境变量PATH中找这个程序
char * 逐个列举
例如这样一个程序
ls –l /mnt ./child/xxx “./child/xxx” NULL
怎样传递这个参数呢?
“ls” “-l” “/mnt” NULL
采用字符指针数组的方式传递参数
char *argv[]={“ls” “-l” “/mnt” NULL }
第一个参数:有二类,char *path—不仅要指定程序的名称也要指定程序的路径
char *file----指定程序的名称,你这个程序的所在路径一定要在环境变量位PATH中找到
第二参数: char *arg …… char *argv[]
execl例子
execl例子
#include "stdio.h"#include "unistd.h"int main(){ printf("exec before\n"); execl("./xxx","./xxx",NULL); printf("exec after\n"); return 0;}execv例子
#include "stdio.h"#include "unistd.h"int main(){ char *buf[]={"./child/xxx",NULL}; printf("exec before\n"); execv("./child/xxx",buf); printf("exec after\n"); return 0;}execvp例子
#include "stdio.h"#include "unistd.h"int main(){ char *buf[]={"xxx",NULL}; printf("exec before\n"); execvp("xxx",buf); printf("exec after\n"); return 0;}
0 0
- 笔记二:进程间的通信(fork、孤儿进程,僵死进程等)
- 孤儿进程、僵死进程
- 僵死进程和孤儿进程
- 僵死进程和孤儿进程
- 僵死进程与孤儿进程
- 僵死进程和孤儿进程
- 僵死进程与孤儿进程
- 孤儿进程与僵死进程
- 孤儿进程与僵死进程
- 有关僵死进程和孤儿进程的小结
- 通俗易懂的“僵死进程与孤儿进程”讲解
- Liunx下的僵死进程和孤儿进程
- linux 中的僵死进程和孤儿进程
- fork产生僵死子进程的问题
- 僵死进程和孤儿进程以及精灵进程
- Unix进程关系—僵死进程与孤儿进程
- Linux中的僵死进程(01)---僵死进程的概念
- linux进程详解:fork进程、孤儿进程、僵尸进程
- Spark 体系架构
- ubuntu14.04配置opencv3.2官网教程
- 关于使用TabLayout自定义样式的问题总结
- Struts处理文件上传
- 从 View 绘制谈性能优化
- 笔记二:进程间的通信(fork、孤儿进程,僵死进程等)
- C++之浅谈继承
- OS X环境下安装MySQL-python
- Android 性能典范:拯救计划
- 一步一步在Windows中使用MyCat负载均衡 上篇
- 每天一题LeetCode[第十四天]
- Android Studio ButterKnife 插件安装使用
- 九、类模板和标准模板库STL(Standard Template Library)
- 基础类(1)