getpid():获取调用进程的ID。
头文件:
#include
#include
系统调用格式:
pid = getpid( )
参数定义:
int pid
返回值:调用进程的进程ID。
getppid():获取调用进程的父进程ID。
头文件:
#include
#include
系统调用格式:
ppid = getppid( )
参数定义:
int ppid
返回值:调用进程的父进程ID。
fork()使用中的注意事项
fork函数创建子进程的执行可以简单用如下几点概括:
1、产生一个新的PCB;
2、父子共享代码区,子复制父的数据区;
3、返回值:父返子进程pid,子返为0;
4、创建后父子的调度平等,系统决定先调度哪一个
进程的创建过程
fork()调用前
父进程 pid=fork( );
if (pid==0)
printf("I'm the child process!\n");
else if (pid>0)
printf("I'm the parent process! \n");
else
printf("Fork fail!\n");
进程的创建过程
fork()调用后
父进程(子进程) pid=fork( );
if (pid==0)
printf("I'm the child process!\n");
else if (pid>0)
printf("I'm the parent process! \n");
else
printf("Fork fail!\n");
示例:
代码:
#include
#include
#include
#include
main()
{
int p,x,ppid,pid;
x=0;
p=fork();
if(p>0) /*如果是父进程*/
{
printf("parent output x=%d\n",++x);
pid=getpid(); /*获取进程自身的ID号*/
printf("Thi id number of parent is:pid=%d\n",pid);
printf("In the parent: p=%d\n",p);
}
else /*如果是子进程*/
{
printf("child output x=%d\n",++x);
pid=getpid();
printf("Thi id number of child is:pid=%d\n",pid);
ppid=getppid(); /*获取父进程自身的ID号*/
printf("Thi id number of parent is:ppid=%d\n",ppid);
printf("In the child: :p=%d\n",p);
}
}
运行结果:
分析:
根据结果,程序先执行父进程,输出x的值为1,然后输出其ID值,父进程返回的值为子进程的ID值,所以pid返回父进程自身ID值为17591,而p返回它子进程的ID值为17592
父进程执行完毕后执行子进程,子进程拷贝父进程代码,对于子进程而言,x初始值仍为0,所以执行子进程代码时,输出的x值为1,接着输出子进程本身的ID值为17952,它的父进程的ID值为1410(不明白为什么和上面输出的父进程ID值不同),该子进程没有子进程,所以返回的值为0,表示它未链接到下一个子进程。
vfork ( )是创建进程的一个快速函数,其系统调用格式、参数定义以及所需的头文件与fork()相同
创建进程的过程可以简单描述如下。
创建一个新的PCB;
父子进程共享相同的代码区和数据区;
创建后子进程先于父进程执行。
与fork函数区别:
fork():子进程拷贝父进程的数据段,代码段;
vfork():子进程与父进程共享数据段。
fork():创建子进程后,父子进程的执行次序不确定;
vfork():***创建子进程后,保证子进程先运行***,在子进程调用exec或exit之后父进程才能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
在后续的进程通信实验中,要慎重使用vfork( )创建进程。
vfork例子:
代码
#include
#include
#include
#include
main()
{
int p,x;
x=1;
p=vfork();
if (p>0)
printf("parent output x=%d\n",++x);
else
printf("child output x=%d\n",++x);
}
结果:
vfork函数永远先执行子进程,所以,先打印else之后的语句,x=2
接着执行父进程,父子进程共享代码段,且未执行exec或exit,所以父进程一直未执行,返回一个乱码(不太明白这里)
将上述代码中的vfork改为fork函数则:
fork函数随机先执行父进程或子进程,根据结果,先执行父进程,输出x的值为2;子进程拷贝父进程代码,对于子进程而言,x初始值仍为1,所以执行子进程代码时,输出的x值为2
头文件
#include
区别:
exit():
终止调用进程的执行。在调用exit()之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,即“清理I/O缓冲”。
_exit()函数
终止调用进程的执行,返回进程状态,但不关闭文件,不清除输出缓存
解释:
prntf函数将输出结果先保存到缓冲池中(暂存)
输出时将缓冲池内的结果清空并保存,才能输出完整内容
且 printf 函数遇到’\n’符号时,自动将缓冲池内的暂存的结果取出(即保存缓冲池内内容)
exit函数
终止程序时清空缓冲池(将缓冲池内暂存的内容全部保存并输出)所以可以输出结果
_exit函数
终止程序时不保存缓冲池内的内容,所以无输出结果
示例代码:
#include
#include
main()
{
printf("using exit()");
printf("content in buffer");
exit(0);
}
结果:输出两条语句
分析:exit(0)退出程序清除缓存,即缓冲区内暂存的输出结果全部可以被保存,全部都输出
上述代码中exit(0)改为_exit(0)
#include
#include
main()
{
printf("using _exit()");
printf("content in buffer");
_exit(0);
}
则:无打印结果,程序直接退出
分析:
_exit(0)退出时不清空缓存,在将输出结果写入文件之前已经退出,所以没有输出结果
将上述代码中两条输出语句中都加入’\n’符号
则含有_exit(0)函数的代码也出现了输出语句
分析:
因为printf函数遇到\n符号时自动将数据从缓冲池中取出,即保存了缓冲池内的输出结果,所以可以输出
查看进程树:
使用pstree命令,及tree命令查看进程pstree工具可以查看进程的树型结构,tree工具可以查看目录的树形结构
参考资料1
参考资料2
参考资料3