Linux 进程及其创建
来源:互联网 发布:老外吃中国菜知乎 编辑:程序博客网 时间:2024/04/24 15:53
1、Unix中的父子进程,unix是多进程操作系统,进程的启动也是具有先后顺序的,一般的情况下是系统先启动0进程 ,然后由0进程启动进程1和进程2,在由进程1和进程2启动其他进程。
2、unix中进程由进程PID唯一标识;
函数getpid()可以获取当前进程PID;
函数getppid()用于获取当前进程父进程的PID;
函数getuid()用于获取当前用户的ID。
3、fork()函数创建子进程
fork()是通过赋值父进程的资源来创建子进程,子进程将会复制父进程除了代码区之外的所有区域,包括缓存。
pid_t fork()函数成功执行范围子进程PID或者0,而失败返回-1,所以可以通过返回值来隔离出父子进程。
用fork()创建一个子进程,子进程会从fork()当前位置执行代码,fork()之前的代码只有父进程执行;
fork()函数会返回两次,父进程返回的是子进程的PID,而子进程返回0.
#include <stdio.h>#include <stdlib.h>#include <unistd.h>void main(){ printf("begin\n"); pid_t pid = fork(); printf("end%d\n",pid);}后面的 printf("end%d\n",pid)父子进程都会执行,打印出各自的返回值,一个是子进程的PID,一个是子进程返回的0.
4.根据返回值隔离出父子进程
//捕捉父子进程#include <stdio.h>#include <unistd.h>void main(){//父子进程使用不同的分支执行不同的事 pid_t pid = fork(); //printf("%d\n",pid); if (!pid){//父子进程都会执行判断,但是只有子进程可以进来 printf("我是子进程%d,我的父进程是%d\n",getpid(),getppid()); } else{//父进程执行的分支,子进程不会执行 printf("我是父进程%d,我的子进程是%d\n",getpid(),pid); }}
上面的代码根据返回值隔离出了父子进程,可以在各自的返回内执行各自的代码。
5、父子进程出出现了对文件的操作
用fork()创建子进程时,如果有文件描述符存在,则子进程会赋值文件描述符,但是不会赋值文件表,此时父子进程会公用一个文件表,意思就是说父子进程的文件描述符对应的是同一张文件表,所以操作的是同一个文件。
//进程的文件测试#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>void main(){ //pid_t pid = fork();//如果这样会出现什么效果,父进程和子进程都有自己的描述符,和文件表。 int fd = open("a.txt",O_RDWR|O_CREAT|O_TRUNC,0666); if (fd == -1) perror("open"),exit(-1); pid_t pid = fork(); if (pid == 0){ write(fd,"hello",5); close(fd); exit(0); } write(fd,"12345",5); close(fd);}上面代码的执行结果表现为子进程首先写进了hello到a.txt中,随后父进程将12345追加到hello后面(这里要说明的一点是父子进程的执行先后是随机的),为什么父进程不是将原来的hello覆盖掉呢?这是因为父子进程的文件描述符对应了一张文件表,而子进程写完之后,它的文件偏移等信息会反应到文件表中,父进程进行写操作的时候,子进程造成的文件偏移是保留下来了的。如果把fork()函数放到最开始执行,则文件描述符和文件表都会被复制,此时的执行才表现为12345覆盖掉hello。
6、fork创建的子进程,父子进程随机运行,如果子进程先结束,就会给父进程发送消息,让父进程回收子进程的资源,如果父进程没哟收到子进程发送的消息,则子进程的资源无法回收,编程僵尸进程。
如果父进程先于子进程结束,则子进程会编程孤儿进程,在unix进程管理中,此时孤儿进程会被进程1 init接管,此时init进程 就是新的父进程,但是在我的系统下Ubuntu14.04LTS中,表现出来的却是被一个叫做init-user的进程接管了。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(){ pid_t pid = fork(); if (!pid){//子进程 printf("子进程是%d,父进程是%d\n",getpid(),getppid()); sleep(3); printf("子进程是%d,父进程是%d\n",getpid(),getppid()); exit(0); } sleep(1); if (pid){ printf("pid = %d\n",getpid()); } exit(0);}程序中有意设置延迟让父进程先结束,此时表现出来的是父进程结束之后子进程被init-user接管,而不是init进程接管。
而这个进程PID4173不是固定的,重新执行就变成了其他的数字。我给这个进程发送信号9,想杀死这个进程,指令如下:
kill -9 4173,它的效果就是一个注销的效果,立马回到刚启动好系统的登录页面。我想这是linux的进程优化吧。让一个叫init--user的进程来接管孤儿进程,而不是init进程来接管。
7、进程的退出
进程的正常退出表现为:
a、return退出;b、exit()退出;c、执行_exit()或_Exit()退出;d、最后一个线程退出;e、主线程退出
进程的非正常退出表现为:
a、被信号打断
b、最后一个线程被取消
//观察fa函数会被几次调用//理论:可以使用atexit注册一些函数,这些函数会在执行exit或者return之前调用一次。#include <stdio.h>#include <stdlib.h>void fa(void){ printf("fa called\n");}int main(){ atexit(fa);//注册退出前的调用函数 //printf("begin\n"); pid_t pid=fork(); if (!pid){//取子进程 printf("begin\n"); //_exit(0); } //exit(0); //_exit(0);不会打印fa函数的内容,代表立即退出 //else{ // printf("end\n"); //exit(0);//父进程结束,将不会执行下面的return //} printf("end\n"); return 0;//调用fa函数}
8、wait(),waitpid()
两个函数均可让父进程等待子进程的结束,并且取得子进程的退出状态和退出码(就是return后面的值或者exit()括号中的值)。
两者的区别在于wait()比较固定,等待任意子进程的结束即可,然后返回结束子进程PID,而waitpid()表现更为灵活,可以选择等待某一个子进程。
wait函数如下:
pid_twait(int *statuc),其中statuc参数是一个传出参数,用来带出结束子进程的退出码和退出状态;
//进程阻塞#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/wait.h>int main(){ pid_t pid = fork(); if (!pid){ sleep(2); printf("子进程%d即将结束",getpid()); exit(100); } int status; pid_t wpid = wait(&status);//如果子进程不结束,父进程将会阻塞 printf("等待到了%d的退出\n",wpid); if (WIFEXITED(status)){ printf("正常退出,退出码:%d\n",WEXITSTATUS(status)); }}
宏函数WIFWXITED(status)可以判断正常退出;
宏函数WEXITSTATUS(status)可以取出退出码;
pid_twaitpid(pid_t pid,int *status,int option)
参数status和wait()一样,pid可以设定等待哪些子进程,option可以设定是否等待。
pid 的值可能是:
==-1 等待任意子进程,与wait()等效;
>0 等待指定子进程
==0 等待本进程组任意子进程
<-1 等待进程组ID等于pid绝对值的任一子进程
option的值:
0 阻塞,父进程等待;
WNOHANG 不阻塞,直接返回0
返回值:有子进程结束时返回子进程pid
出错返回-1
如果阻塞方式,没有子进程结束继续等待;
如果是WNOHANG,没有子进程返回0;
//waitpid函数#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>#include <unistd.h>int main(){ pid_t pid = fork(); if (pid == -1) perror("fork"),exit(-1); if (!pid){ sleep(1); printf("子进程%d即将结束\n",getpid()); exit(100); } pid_t pid2 = fork(); if (!pid2){ sleep(3); printf("子进程%d即将结束\n",getpid()); exit(200); } int status; pid_t wpid = waitpid(pid2,&status,/*WNOHANG*/0); if(WIFEXITED(status)){ printf("等待到了%d子进程,退出码:%d\n",wpid,WEXITSTATUS(status)); } }
- Linux 进程及其创建
- linux守护进程及其创建
- linux守护进程及其创建
- linux守护进程及其创建
- linux守护进程及其创建
- linux C 守护进程及其创建
- 初始Linux下进程及其创建
- Linux下进程的创建及其使用管道进行进程之间的通讯[00原创]
- 【归纳总结】Unix/linux下的进程管理(二):创建进程的函数及其应用、对比
- Linux 中的进程及其状态
- Linux - 进程 (二) 进程创建
- linux 进程编程:进程创建
- [linux] 创建daemon进程
- Linux 进程创建
- Linux版进程创建
- linux 创建进程
- linux 管道创建进程
- Linux创建进程
- 感冒的一般过程
- Android6.0权限分析
- 软件测试必须要知道十个关键点
- 用PDB库调试Python程序
- T-SQL Part VIII: CROSS APPLY, OUTER APPLY
- Linux 进程及其创建
- HTML判断判断客户端是IOS还是Android
- WebBrowser 遇到类似银行网页需要安装插件才显示的文本框问题
- 【FragmentTabHost】FragmentTabHost的使用
- 给 Android 开发者的 RxJava 详解
- ccah-500 第22题 Which process instantiates user code, and executes map and reduce tasks on a cluster r
- php如何实现文件下载
- chronoment暂停方法的实现
- 乐学成语