进程标识符

#include <unistd.h>

pid_t getpid(void);  //获得调用进程的PID
pid_t getppid(void); //获得调用进程的父进程的PID
uid_t getuid(void);  //返回调用进程的实际用户ID
uid_t geteuid(void); //返回调用进程的有效用户ID
gid_t getgid(void0;  //返回调用进程的实际组ID
gid_t getegid(void); //返回调用进程的有效组ID

fork函数

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

e8-1演示了fork函数,从中可以看出,子进程对变量所做的修改并不影响父进程中该变量。

#include "apue.h"

int glob = 6;
char buf[] = "a write to stdout\n";

int main(void) {
  int var;
  pid_t pid;
  var = 88;

  if (write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) - 1)
    err_sys("write error");

  if ((pid = fork()) < 0) {
    err_sys("fork error");
  } else if (pid == 0) {
    glob ++;
    ++ var;
  } else {
    sleep(2);
  }

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

C标准IO库是有缓冲区的。如果标准输出连接的是终端设备,则它是行缓冲的。否则它是全缓冲的。所以在终端中运行该程序,在fork时,缓冲区已经被刷新了,因为上面的printf输出的刚好是一行。子进程的缓冲区和父进程完全一致,所以它的缓冲区也是已经被刷新了。所以printf只输出一次。 如果将其标准输出重定向到一个文件,则会输出2次。

wait和waitpid函数

当一个进程终止时,内核向其父进程发送SIGCHLD信号。如果进程在收到SIGCHLD信号时调用wait,则可期望wait会立刻返回。如果在任意时刻调用,则进程可能会阻塞。

#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);

wait和waitpid的区别如下:

  • 在一个进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞。
  • waitpid并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制特定的子进程
    如果一个进程终止了,并且是一个僵尸进程,则wait立刻返回,并取得该子进程的状态,否则wait使调用者一直阻塞到一个子进程终止。
    这两个函数的参数statloc是一个整型指针。如果statloc不是空指针,则终止进程的终止状态就存放在它所指向的单元里。如果不关心终止状态,则可以置为空指针。
    终止原因可以通过以下的宏来查询
    说明
    WIFEXITED(status) 若为正常终止子进程,返回真。对于这种情况可以通过WEXITSTATUS来取得返回值
    WIFSIGNALED(status) 若为异常终止子进程返回,则为真。可通过WTERMSIG,来获得终止的信号。
    WIFSTOPPED(status) 若为当前暂停子进程的返回状态,则为真。可通过WSTOPSIG,取得子进程暂停的信号
    WIFCONTINUED(status) 若在作业控制暂停后,已经继续的子进程,则为真。