`
brxonline
  • 浏览: 64266 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

UNIX编程(8)-进程控制

    博客分类:
  • C
 
阅读更多

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

 

分享到:
评论

相关推荐

    UNIX网络编程-第2卷-进程间通讯

    《UNIX网络编程-第2卷-进程间通讯》是一本深入探讨UNIX系统中进程间通信(Inter-Process Communication, IPC)的经典著作。该书详细阐述了如何在多进程环境中实现有效的数据交换,这对于理解操作系统原理、开发高效...

    unix多进程-多进程编程

    ### Unix多进程编程知识点 #### 1. Unix进程概述 Unix系统是一种多用户、多任务的操作系统,支持多个进程同时运行。进程是程序在计算机上的一次执行过程,每个进程都拥有自己的地址空间、数据栈以及其他运行时资源...

    unix实验---进程间通信实验源码

    本实验源码着重展示了无名管道(unnamed pipe)和IPC通信的C语言实现,这对于理解Unix系统编程和多进程协作至关重要。 无名管道是一种半双工的通信方式,数据只能单向流动,且只存在于内存中,不持久化存储。其工作...

    UNIX编程艺术 - 扫描版 - 书签

    根据提供的信息,我们可以了解到这是一本关于《UNIX编程艺术》的经典书籍,该书提供了高清扫描版本,并且包含完整的书签,方便读者进行阅读与查阅。接下来,我们将从这本书的主题出发,探讨几个重要的UNIX编程概念与...

    Unix编程艺术--完整书签版

    《Unix编程艺术》解释了Unix的用户和组概念,以及如何通过chmod、chown等命令控制文件和目录的访问权限。同时,书中也讨论了如何避免常见的安全风险,如缓冲区溢出和权限滥用。 最后,书中还介绍了版本控制系统Git...

    UNIX网络编程_卷2_进程间通信【第二版】源码

    UNIX网络编程----进程间通信----卷2【第二版】源码

    UNIX环境高级编程-009_进程关系

    《UNIX环境高级编程》第9章主要讨论的是进程间的关系,包括进程的父子关系、进程组、对话期的概念,以及登录shell和相关进程之间的交互。这一章的内容是建立在前一章关于进程控制的基础之上的,进一步深入探讨了进程...

    UNIX网络编程-第2卷-进程间通信

    本书全面深入地讲述了各种进程间通信(IPC)形式,它们是几乎所有复杂精致的UNIX程序的性能之关键。从网络编程角度看,理解IPC也是理解如何开发不同主机间网络应用程序的必要条件。本书从对Posix IPC和System V IPC...

    UNIX高级编程5-6(大师著作)

    8. 错误处理与调试技巧:在UNIX编程中,良好的错误处理是不可或缺的。书中会讲解如何正确捕获和处理错误,以及使用调试工具如gdb进行程序调试。 通过学习《UNIX高级编程》,程序员不仅可以掌握UNIX编程的核心技术,...

    UNIX----系统编程

    - **POSIX标准**:提供了跨平台的UNIX编程接口,如pthread库用于线程编程。 通过深入学习和实践以上知识点,你将能够熟练地进行UNIX系统编程,开发出高效、稳定的应用程序。记得结合《UNIX系统编程》这样的参考...

    UNIX环境高级编程-pdf

    《UNIX环境高级编程》是一本深受程序员和系统管理员喜爱的经典之作,主要针对那些希望深入理解UNIX操作系统,并能熟练进行...无论是自学还是作为参考手册,这本书及其相关资料都能为你的UNIX编程之路提供强大的支持。

    Java网络编程--Unix域协议:实现

    总结来说,Java网络编程虽然主要关注基于TCP和UDP的网络通信,但理解Unix域协议的实现有助于在特定场景下实现更高效、低延迟的进程间通信。通过JNI,开发者可以利用C/C++实现的Unix域协议功能,提升Java应用的性能。...

    unix网络编程--第一卷----套接口API

    《UNIX网络编程——第一卷——套接口API》是网络编程领域的经典之作,尤其在UNIX操作系统环境下,这本书被视为不可或缺的学习资源。作者深入浅出地讲解了网络通信的基础理论和实际操作,帮助开发者理解如何利用套...

    UNIX网络编程_卷2_进程间通信

    《UNIX网络编程.卷2:进程间通信(第2版)》这本书是W.Richard Stevens所著的网络编程领域的权威之作。本书详细介绍了UNIX系统中进程间通信(IPC)的各种形式,这些通信机制对于提高UNIX程序性能至关重要,同时是开发...

    Unix编程艺术/Unix环境高级编程(第二版)/Unix网络编程(第二版)

    《Unix编程艺术》、《Unix环境高级编程(第二版)》和《Unix网络编程(第二版)》是三本在IT领域中具有深远影响力的经典著作,涵盖了Unix操作系统的核心概念、系统调用、进程管理、文件操作、网络通信等多个重要主题...

    unix环境高级编程----------------------------------

    8. **进程间通信(IPC)**:Unix提供了多种进程间通信方式,如管道、消息队列、共享内存、信号量等。这些机制用于进程间的协调和数据交换。 9. **标准库与C语言接口**:Unix标准库如`stdio.h`, `stdlib.h`, `string...

    笔记_UNIX环境网络编程卷二进程间通信_中文第二版.pdf

    笔记_UNIX环境网络编程卷二进程间通信_中文第二版

    UNIX环境高级编程 -- PDF格式

    《UNIX环境高级编程》是一本深受程序员喜爱的经典教程,它深入介绍了在UNIX操作系统环境下进行系统级编程的各种技术和方法。这本书不仅适用于C++开发者,也对任何想要深入理解UNIX系统的程序员都极具价值。以下是对...

Global site tag (gtag.js) - Google Analytics