linux-进程控制-基于C语言

一、所涉及的系统调用

在UNIX/LINUX中fork( )是一个非常有用的系统调用,但在UNIX/LINUX中建立进程除了fork( )之外,也可用与fork( ) 配合使用的exec( )。

1、exec()系列

系统调用exec( )系列,也可用于新程序的运行。fork( )只是将父进程的用户级上下文拷贝到新进程中,而exec( )系列可以将一个可执行的二进制文件覆盖在新进程的用户级上下文的存储空间上,以更改新进程的用户级上下文。exec( )系列中的系统调用都完成相同的功能,它们把一个新程序装入内存,来改变调用进程的执行代码,从而形成新进程。如果exec( )调用成功,调用进程将被覆盖,然后从新程序的入口开始执行,这样就产生了一个新进程,新进程的进程标识符id 与调用进程相同。

exec( )没有建立一个与调用进程并发的子进程,而是用新进程取代了原来进程。所以exec( )调用成功后,没有任何数据返回,这与fork( )不同。exec( )系列系统调用在UNIX系统库unistd.h中,共有execl、execlp、execle、execv、execvp五个,其基本功能相同,只是以不同的方式来给出参数。

一种是直接给出参数的指针,如:

int execl(path,arg0[,arg1,...argn],0);
char *path,*arg0,*arg1,...,*argn;

另一种是给出指向参数表的指针,如:

int execv(path,argv);
char *path,*argv[ ];

具体使用可参考有关书。

2、exec()和fork()联合使用

系统调用exec和fork( )联合使用能为程序开发提供有力支持。用fork( )建立子进程,然后在子进程中使用exec( ),这样就实现了父进程与一个与它完全不同子进程的并发执行。

一般,wait、exec联合使用的模型为:

int status;
if (fork() == 0) 
{
   ...........
   execl(...);
   ...........;
}
wait(&status);

3、wait()

等待子进程运行结束。如果子进程没有完成,父进程一直等待。wait( )将调用进程挂起,直至其子进程因暂停或终止而发来软中断信号为止。如果在wait( )前已有子进程暂停或终止,则调用进程做适当处理后便返回。

系统调用格式:

int wait(status) 
int *status;

其中,status是用户空间的地址。它的低8位反应子进程状态,为0表示子进程正常结束,非0则表示出现了各种各样的问题;高8位则带回了exit( )的返回值。exit( )返回值由系统给出。

核心对wait( )作以下处理:

  1. 首先查找调用进程是否有子进程,若无,则返回出错码;
  2. 若找到一处于“僵死状态”的子进程,则将子进程的执行时间加到父进程的执行时间上,并释放子进程的进程表项;
  3. 若未找到处于“僵死状态”的子进程,则调用进程便在可被中断的优先级上睡眠,等待其子进程发来软中断信号时被唤醒。

4、exit()

终止进程的执行。

系统调用格式:

void exit(status)
int status;

其中,status是返回给父进程的一个整数,以备查考。

为了及时回收进程所占用的资源并减少父进程的干预,UNIX/LINUX利用exit( )来实现进程的自我终止,通常父进程在创建子进程时,应在进程的末尾安排一条exit( ),使子进程自我终止。exit(0)表示进程正常终止,exit(1)表示进程运行有错,异常终止。

如果调用进程在执行exit( )时,其父进程正在等待它的终止,则父进程可立即得到其返回的整数。核心须为exit( )完成以下操作:

  1. 关闭软中断
  2. 回收资源
  3. 写记帐信息
  4. 置进程为“僵死状态”

二、参考例程

#include<stdio.h>
#include<unistd.h>

int main() {
    int pid;
    pid = fork();         /*创建子进程*/
    switch (pid) {
        case -1:                          /*创建失败*/
            printf("fork fail!\n");
            exit(1);
        case 0:                                 /*子进程*/
            execl("/bin/ls", "ls", "-l", "-color", NULL);
            printf("exec fail!\n");
            exit(1);
        default:                                 /*父进程*/
            wait(NULL);                  /*同步*/
            printf("ls completed !\n");
            exit(0);
    }
    return 0;
}

三、运行结果

该程序的作用就是执行以下命令

ls -l -color 

(按倒序)列出当前目录下所有文件和子目录;

ls completed!

四、分析原因

程序在调用fork( )建立一个子进程后,马上调用wait( ),使父进程在子进程结束之前,一直处于睡眠状态。子进程用exec( )装入命令ls ,exec( )后,子进程的代码被ls的代码取代,这时子进程的PC指向ls的第1条语句,开始执行ls的命令代码。

注意: 在这里wait( )给我们提供了一种实现进程同步的简单方法。

posted @ 2020-08-11 21:55  漫漫长夜何时休  阅读(198)  评论(0编辑  收藏  举报