操作系统之进程的创建与结束

Linux系统中进程的创建

getpid函数与getppid函数

getpid():获取调用进程的ID。
头文件:
#include
#include
系统调用格式:
pid = getpid( )
参数定义:
int pid
返回值:调用进程的进程ID。

getppid():获取调用进程的父进程ID。
头文件:
#include
#include
系统调用格式:
ppid = getppid( )
参数定义:
int ppid
返回值:调用进程的父进程ID。

Linux中创建进程的fork()系统调用

  1. 创建一个新进程。
  2. 系统调用格式: p=fork( );
  3. 参数定义: int p;
  4. 返回值:子进程中为0,父进程中为子进程ID,出错为-1;
  5. fork( )返回值pid意义如下:
    p=0:在子进程中,p变量保存的fork()返回值为0,表示当前进程是子进程;
    p>0:在父进程中,p变量保存的fork()返回值为子进程的ID值(进程唯一标识符
    p=-1:创建失败

fork()使用中的注意事项

  1. 子进程是父进程的一个拷贝。即子进程从父进程得到了数据段和堆栈段的拷贝,需要分配内存 。
  2. fork返回后,子进程和父进程都从调用fork函数的下一条语句开始执行。 父进程与子进程并发执行。
  3. 父进程与子进程的不同:
    fork的返回值不同
    父进程中的返回值为子进程的进程号
    子进程返回 0。

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);
}
}

运行结果:

操作系统之进程的创建与结束_第1张图片
分析:
根据结果,程序先执行父进程,输出x的值为1,然后输出其ID值,父进程返回的值为子进程的ID值,所以pid返回父进程自身ID值为17591,而p返回它子进程的ID值为17592
父进程执行完毕后执行子进程,子进程拷贝父进程代码,对于子进程而言,x初始值仍为0,所以执行子进程代码时,输出的x值为1,接着输出子进程本身的ID值为17952,它的父进程的ID值为1410(不明白为什么和上面输出的父进程ID值不同),该子进程没有子进程,所以返回的值为0,表示它未链接到下一个子进程。

vfork函数调用

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

exit函数与_exit函数

头文件
#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

你可能感兴趣的:(Linux,linux,c语言)