5.进程控制

2016-12-14  本文已影响0人  大雄good

进程控制

这一节主要介绍Unix系统的进程控制,包括创建新进程、执行进程和进程终止。由于前面Linux学习部分有了一定的进程控制的理论知识,本节更多是结合实践代码介绍。

1.fork

一个现有进程通过调用fork函数创建一个新进程。

#include<unistd.h>
pid_t fork(void)
/* 返回值:子进程返回0,父进程返回子进程ID;若出错返回-1 */

子进程ID为0原因是因为系统中ID为0的进程总是由内核交换程序使用,所以子进程ID不可能为0。执行fork之后,子进程是父进程的副本,获得父进程的数据空间、堆和栈的副本。下面通过一个实例演示fork函数:

#include "apue.h"

int     globvar = 6;        /* external variable in initialized data */
char    buf[] = "a write to stdout\n";

int
main(void)
{
    int     var;        /* automatic variable on the stack */
    pid_t   pid;

    var = 88;
    if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
        err_sys("write error");
    printf("before fork\n");    /* we don't flush stdout */

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {      /* child */
        globvar++;              /* modify variables */
        var++;
    } else {
        sleep(2);               /* parent */
    }

    printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar,
      var);
    exit(0);
}

运行程序得到:

fork

上述结果中,先运行了子进程,再运行了父进程(一般希望子进程先运行,但是不一定),子进程拷贝了父进程的数据空间,并对globvarvar执行加1操作,此时子进程和父进程都有各自的数据空间。

父进程和子进程的文件共享如下图所示:

子进程和父进程文件共享

fork主要有两种用法:

2.vfork

由Linux内核设计的理论知道,vfork的原理是,父进程产生一个子进程,并阻塞父进程,子进程使用父进程的地址空间,直到子进程执行完毕,父进程继续执行。通过下面代码分析:

#include "apue.h"

int     globvar = 6;        /* external variable in initialized data */

int
main(void)
{
    int     var;        /* automatic variable on the stack */
    pid_t   pid;

    var = 88;
    printf("before vfork\n");   /* we don't flush stdio */
    if ((pid = vfork()) < 0) {
        err_sys("vfork error");
    } else if (pid == 0) {      /* child */
        globvar++;              /* modify parent's variables */
        var++;
        _exit(0);               /* child terminates */
    }

    /* parent continues here */
    printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar,
      var);
    exit(0);
}

在子进程中对globvarvar执行了加1操作,因为使用的父进程地址空间,因此相对于修改了父进程数据,运行该程序可以得到结果:

vfork

3.进程终止

进程终止时,内核逐个检查所有活动进程,判断它是否是正要终止进程的子进程,如果是,则该进程的父进程ID就改为1,保证每个进程都有父进程。

如果子进程在父进程之前终止,内核为每个终止子进程保存一定量的信息,所以当终止进程的父进程调用waitwaitpid时,可以得到这些信息(包括进程ID、进程终止状态以及使用的CPU时间总量)。内核可以释放终止进程所使用的所有存储区,关闭其所有文件夹。一个已经终止,但是父进程未对其进行善后的进程称为僵尸进程

4.wait和waitpid

当一个进程终止时,内核向其父进程发送SIGCHLD信号,因为子进程终止是一个异步时间,所以这个信号也是内核向父进程发的异步通知,父进程可以忽略该信号或者调用waitwaitpid。若是调用waitwaitpid,可能发生下面情况:

#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
/* 返回值:成功返回进程ID,出错返回0或-1 */

这两个函数区别如下:

如果一个子进程已经停止,且是一个僵尸进程,则wait立即返回并取得该子进程的状态;否则wait使其调用者阻塞,直到一个子进程终止,返回终止子进程的ID。

5.竞争条件

当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程运行的顺序时,我们认为发生了竞争条件。例如在fork后无法预料那个进程先运行。

这里给出一种解决方法:

#include "apue.h"

static void charatatime(char *);

int
main(void)
{
    pid_t   pid;

    TELL_WAIT();

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {
        WAIT_PARENT();      /* parent goes first */
        charatatime("output from child\n");
    } else {
        charatatime("output from parent\n");
        TELL_CHILD(pid);
    }
    exit(0);
}

static void
charatatime(char *str)
{
    char    *ptr;
    int     c;

    setbuf(stdout, NULL);           /* set unbuffered */
    for (ptr = str; (c = *ptr++) != 0; )
        putc(c, stdout);
}

上述代码即在子进程执行时,先等待父进程执行,而父进程内容中执行完毕时通知子进程当前进程执行完毕。

6.exec

fork创建新进程之后,往往需要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后进程ID并未改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段。

有7种不同的exec可供使用,它们常称为exec函数:

#include <unistd.h>
int execl(const char *pathname, const char *arg0, ... /* (char *)0 */ );
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ... /* (char *)0, char *const envp[] */ );
int execve(const char *pathname, char *const argv[], char *const envp[]); int execlp(const char *filename, const char *arg0, ... /* (char *)0 */ ); int execvp(const char *filename, char *const argv[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
/* 返回值:出错返回-1,成功不返回*/

它们之间的关系可以由下图得到:

exec
上一篇下一篇

猜你喜欢

热点阅读