UNIX编程(8)-进程控制

1.进程标识符

每个进程都有一个非负整数表示的唯一进程ID

 

#include <unistd.h>

pid_t getpid(void);

Returns: process ID of calling process

 

pid_t getppid(void);

Returns: parent process ID of calling process

 

uid_t getuid(void);

Returns: real user ID of calling process

 

uid_t geteuid(void);

Returns: effective user ID of calling process

 

gid_t getgid(void);

Returns: real group ID of calling process

 

gid_t getegid(void);

Returns: effective group ID of calling process

2.fork函数

fork函数创建一个新的进程,调用一次返回两次,子进程的返回值是0,父进程的返回值是子进程的进程ID

 

#include <unistd.h>

pid_t fork(void);

Returns: 0 in child, process ID of child in parent, 1 on error


例:

#include "apue.h"

int     glob = 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 */
        glob++;                 /* modify variables */
        var++;
    } else {
        sleep(2);               /* parent */
    }

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


3.vfork函数

vfork函数和fork函数类似,但区别在于它并不将父进程的地址空间完全复制到子进程,因为子进程会立即调用exec或exit函数。另一个区别在于vfork保证子进程先运行。

例:

#include "apue.h"

int     glob = 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 */
        glob++;                 /* modify parent's variables */
        var++;
        _exit(0);               /* child terminates */
    }
    /*
     * Parent continues here.
     */
    printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
    exit(0);
}


4.exit函数

5. wait和 waitpid函数

 

#include <sys/wait.h>

pid_t wait(int *statloc);

pid_t waitpid(pid_t pid, int *statloc, int options);

Both return: process ID if OK, 0 (see later), or 1 on error


两函数的区别:在一个子进程终止前wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞

例:

#include "apue.h"
#include <sys/wait.h>

void
pr_exit(int status)
{
    if (WIFEXITED(status))
        printf("normal termination, exit status = %d\n",
                WEXITSTATUS(status));
    else if (WIFSIGNALED(status))
        printf("abnormal termination, signal number = %d%s\n",
                WTERMSIG(status),
#ifdef  WCOREDUMP
                WCOREDUMP(status) ? " (core file generated)" : "");
#else
                "");
#endif
    else if (WIFSTOPPED(status))
        printf("child stopped, signal number = %d\n",
                WSTOPSIG(status));
}
#include "apue.h"
#include <sys/wait.h>

int
main(void)
{
    pid_t   pid;
    int     status;

    if ((pid = fork()) < 0)
        err_sys("fork error");
    else if (pid == 0)              /* child */
        exit(7);

    if (wait(&status) != pid)       /* wait for child */
        err_sys("wait error");
    pr_exit(status);                /* and print its status */

    if ((pid = fork()) < 0)
        err_sys("fork error");
    else if (pid == 0)              /* child */
        abort();                    /* generates SIGABRT */

    if (wait(&status) != pid)       /* wait for child */
        err_sys("wait error");
    pr_exit(status);                /* and print its status */

    if ((pid = fork()) < 0)
        err_sys("fork error");
    else if (pid == 0)              /* child */
        status /= 0;                /* divide by 0 generates SIGFPE */

    if (wait(&status) != pid)       /* wait for child */
        err_sys("wait error");
    pr_exit(status);                /* and print its status */

    exit(0);
}


6.waitid函数

#include <sys/wait.h>

int waitid(idtype_t idtype, id_t id, siginfo_t
 *infop, int options);


7.wait3和wait4函数

#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

pid_t wait3(int *statloc, int options, struct rusage *rusage);

pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);

8.竞争条件

当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程运行的顺序时,则我们认为发生了竞争条件

例:避免竞争

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

 9.exec函数

8.10. exec Functions

We mentioned in Section 8.3 that one use of the fork function is to create a new process (the child) that then causes another program to be executed by calling one of the exec functions. When a process calls one of the exec functions, that process is completely replaced by the new program, and the new program starts executing at its main function. The process ID does not change across an exec, because a new process is not created; exec merely replaces the current processits text, data, heap, and stack segmentswith a brand new program from disk.

There are six different exec functions, but we'll often simply refer to "the exec function," which means that we could use any of the six functions. These six functions round out the UNIX System process control primitives. With fork, we can create new processes; and with the exec functions, we can initiate new programs. The exit function and the wait functions handle termination and waiting for termination. These are the only process control primitives we need. We'll use these primitives in later sections to build additional functions, such as popen and system.

#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 []);

例:

#include "apue.h"
#include <sys/wait.h>

char    *env_init[] = { "USER=unknown", "PATH=/tmp", NULL };

int
main(void)
{
    pid_t   pid;

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {  /* specify pathname, specify environment */
        if (execle("/home/sar/bin/echoall", "echoall", "myarg1",
                "MY ARG2", (char *)0, env_init) < 0)
            err_sys("execle error");
    }

    if (waitpid(pid, NULL, 0) < 0)
        err_sys("wait error");

    if ((pid = fork()) < 0) {
        err_sys("fork error");
    } else if (pid == 0) {  /* specify filename, inherit environment */
        if (execlp("echoall", "echoall", "only 1 arg", (char *)0) < 0)
            err_sys("execlp error");
    }

    exit(0);
}


 

#include "apue.h"

int
main(int argc, char *argv[])
{
    int         i;
    char        **ptr;
    extern char **environ;

    for (i = 0; i < argc; i++)      /* echo all command-line args */
        printf("argv[%d]: %s\n", i, argv[i]);

    for (ptr = environ; *ptr != 0; ptr++)   /* and all env strings */
        printf("%s\n", *ptr);

    exit(0);
}


 

10.更改用户ID 和组ID

 

#include <unistd.h>

int setuid(uid_t uid);

int setgid(gid_t gid);

Both return: 0 if OK, 1 on error


交换实际用户ID和有效用户ID

#include <unistd.h>

   int setreuid(uid_t ruid, uid_t euid);

   int setregid(gid_t rgid, gid_t egid);

Both return: 0 if OK, 1 on error


只更改有效用户ID和有效组ID

 

#include <unistd.h>

int seteuid(uid_t uid);

int setegid(gid_t gid);

Both return: 0 if OK, 1 on error

11.解释器文件

UNIX支持解释器文件,文件的格式如下

#! pathname [ optional-argument ]

12.system函数

 

#include <stdlib.h>

int system(const char *cmdstring);

Returns: (see below)


返回类型说明:

如果fork失败,或者waitpid返回除EINTR之外的出错,则system返回-1,而且errno中设置了错误类型值

如果exec失败,则其返回值如同shell执行了exit(127)一样

否则所有三个函数(fork,exec,waitpid)都执行成功,并且system的返回值是shell的终止状态,其格式已在waitpid中说明

#include "apue.h"
#include <sys/wait.h>

int
main(void)
{
    int      status;

    if ((status = system("date")) < 0)
        err_sys("system() error");
    pr_exit(status);

   if ((status = system("nosuchcommand")) < 0)
       err_sys("system() error");
   pr_exit(status);

   if ((status = system("who; exit 44")) < 0)
       err_sys("system() error");
   pr_exit(status);

   exit(0);
}


 

13.进程会计

需先调用accton命令启动会计事务处理

acct结构体说明:

struct  acct
{
  char   ac_flag;     /* flag (see Figure 8.26) */
  char   ac_stat;     /* termination status (signal & core flag only) */
                      /* (Solaris only) */
  uid_t  ac_uid;      /* real user ID */
  gid_t  ac_gid;      /* real group ID */
  dev_t  ac_tty;      /* controlling terminal */
  time_t ac_btime;    /* starting calendar time */
  comp_t ac_utime;    /* user CPU time (clock ticks) */
  comp_t ac_stime;    /* system CPU time (clock ticks) */
  comp_t ac_etime;    /* elapsed time (clock ticks) */
  comp_t ac_mem;      /* average memory usage */
  comp_t ac_io;       /* bytes transferred (by read and write) */
                      /* "blocks" on BSD systems */
  comp_t ac_rw;       /* blocks read or written */
                      /* (not present on BSD systems) */
  char   ac_comm[8];  /* command name: [8] for Solaris, */
                      /* [10] for Mac OS X, [16] for FreeBSD, and */
                      /* [17] for Linux */
};

 

例:

产生进程会计数据

#include "apue.h"

int
main(void)
{

    pid_t   pid;

    if ((pid = fork()) < 0)
        err_sys("fork error");
    else if (pid != 0) {       /* parent */
        sleep(2);
        exit(2);               /* terminate with exit status 2 */
    }

                               /* first child */
    if ((pid = fork()) < 0)
        err_sys("fork error");
    else if (pid != 0) {
        sleep(4);
        abort();               /* terminate with core dump */
    }

                               /* second child */
   if ((pid = fork()) < 0)
       err_sys("fork error");
   else if (pid != 0) {
       execl("/bin/dd", "dd", "if=/etc/termcap", "of=/dev/null", NULL);
       exit(7);                /* shouldn't get here */
   }

                               /* third child */
   if ((pid = fork()) < 0)
       err_sys("fork error");
   else if (pid != 0) {
       sleep(8);
       exit(0);                /* normal exit */
   }

                               /* fourth child */
   sleep(6);
   kill(getpid(), SIGKILL);    /* terminate w/signal, no core dump */
   exit(6);                    /* shouldn't get here */
}


查看进程会计数据

#include "apue.h"
#include <sys/acct.h>

#ifdef HAS_SA_STAT
#define FMT "%-*.*s  e = %6ld, chars = %7ld, stat = %3u: %c %c %c %c\n"
#else
#define FMT "%-*.*s  e = %6ld, chars = %7ld, %c %c %c %c\n"
#endif
#ifndef HAS_ACORE
#define ACORE 0
#endif
#ifndef HAS_AXSIG
#define AXSIG 0
#endif

static unsigned long
compt2ulong(comp_t comptime)    /* convert comp_t to unsigned long */
{
    unsigned long   val;
    int             exp;

    val = comptime & 0x1fff;    /* 13-bit fraction */
    exp = (comptime >> 13) & 7; /* 3-bit exponent (0-7) */
    while (exp-- > 0)
        val *= 8;
    return(val);
}
int
main(int argc, char *argv[])
{
    struct acct     acdata;
    FILE            *fp;

    if (argc != 2)
        err_quit("usage: pracct filename");
    if ((fp = fopen(argv[1], "r")) == NULL)
        err_sys("can't open %s", argv[1]);
    while (fread(&acdata, sizeof(acdata), 1, fp) == 1) {
        printf(FMT, (int)sizeof(acdata.ac_comm),
            (int)sizeof(acdata.ac_comm), acdata.ac_comm,
            compt2ulong(acdata.ac_etime), compt2ulong(acdata.ac_io),
#ifdef HAS_SA_STAT
            (unsigned char) acdata.ac_stat,
#endif
            acdata.ac_flag & ACORE ? 'D' : ' ',
            acdata.ac_flag & AXSIG ? 'X' : ' ',
            acdata.ac_flag & AFORK ? 'F' : ' ',
            acdata.ac_flag & ASU   ? 'S' : ' ');
    }
    if (ferror(fp))
        err_sys("read error");
    exit(0);
}

14.用户标识


 

 

#include <unistd.h>

char *getlogin(void);

Returns: pointer to string giving login name if OK, NULL on error


15.进程时间

 

#include <sys/times.h>

clock_t times(struct tms *buf);

Returns: elapsed wall clock time in clock ticks if OK, 1 on error

tms结构体说明:


 struct tms {
     clock_t  tms_utime;  /* user CPU time */
     clock_t  tms_stime;  /* system CPU time */
     clock_t  tms_cutime; /* user CPU time, terminated children */
     clock_t  tms_cstime; /* system CPU time, terminated children */
   };

例:

#include "apue.h"
#include <sys/times.h>

static void pr_times(clock_t, struct tms *, struct tms *);
static void do_cmd(char *);

int
main(int argc, char *argv[])
{

    int     i;

    setbuf(stdout, NULL);
    for (i = 1; i < argc; i++)
        do_cmd(argv[i]);    /* once for each command-line arg */
    exit(0);
}

static void
do_cmd(char *cmd)        /* execute and time the "cmd" */
{
     struct tms  tmsstart, tmsend;
     clock_t     start, end;
     int         status;

     printf("\ncommand: %s\n", cmd);

     if ((start = times(&tmsstart)) == -1)    /* starting values */
         err_sys("times error");

     if ((status = system(cmd)) < 0)     /* execute command */
         err_sys("system() error");

     if ((end = times(&tmsend)) == -1)       /* ending values */
         err_sys("times error");

     pr_times(end-start, &tmsstart, &tmsend);
     pr_exit(status);
}
static void
pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend)
{
    static long     clktck = 0;

    if (clktck == 0)    /* fetch clock ticks per second first time */
        if ((clktck = sysconf(_SC_CLK_TCK)) < 0)
            err_sys("sysconf error");
     printf(" real:  %7.2f\n", real / (double) clktck);
     printf(" user:  %7.2f\n",
       (tmsend->tms_utime - tmsstart->tms_utime) / (double) clktck);
     printf(" sys:   %7.2f\n",
       (tmsend->tms_stime - tmsstart->tms_stime) / (double) clktck);
     printf(" child user:   %7.2f\n",
       (tmsend->tms_cutime - tmsstart->tms_cutime) / (double) clktck);
     printf(" child sys:    %7.2f\n",
       (tmsend->tms_cstime - tmsstart->tms_cstime) / (double) clktck);
}

猜你喜欢

转载自brxonline.iteye.com/blog/1120401