Linux 进程及其创建
Posted uestclr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 进程及其创建相关的知识,希望对你有一定的参考价值。
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 进程及其创建的主要内容,如果未能解决你的问题,请参考以下文章