/* * Fatal error related to a system call. * Print a message and terminate. */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, errno, fmt, ap); va_end(ap); exit(1); } /* * Print a message and return to caller. * Caller specifies "errnoflag". */ static void err_doit(int errnoflag, int error, const char *fmt, va_list ap) { char buf[MAXLINE]; vsnprintf(buf, MAXLINE-1, fmt, ap); if (errnoflag) snprintf(buf+strlen(buf), MAXLINE-strlen(buf)-1, ": %s", strerror(error)); strcat(buf, "\n"); fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(NULL); /* flushes all stdio output streams */ }
#include "myapue.h" int globvar = 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"); printf("before fork\n"); if((pid = fork()) < 0){ err_sys("fork error"); }else if(pid == 0){ globvar++; var++; }else sleep(2); printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); exit(0); }
(1)<7>
STDIN_FILENO、STDOUT_FILENO:<unistd.h>,指定标准输入和标准输出的文件描述符。
(2)<184>
因为缓冲区buf已经用已知字符串初始化,其长度是固定的,所以sizeof是在编译时计算缓冲区长度。
(3)
write函数不带缓冲,
printf函数带缓冲(标准IO库)
如果标准输出连接到终端设备,则它是行缓冲;否则它是全缓冲的(此处在进程终止时,其缓冲区中的内容写到相应文件中)。
#include "myapue.h" int globvar = 6; int main(void) { int var; pid_t pid; var = 88; printf("before vfork\n"); if((pid = vfork()) < 0) err_sys("vfork error"); else if(pid == 0){ globvar++; var++; _exit(0); } printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); exit(0); }
(1)<187>
vfork函数:
1、它不将父进程的地址空间完全复制到子进程。子进程应立即调用exec或exit函数,否则它在父进程的空间运行,可能会带来未知的结果。
2、vfork保证子进程先运行,在它调用exec或exit之后父进程才能被调度运行。
(2)<159>
_exit函数:正常终止程序,并立即进入内核,不执行清理处理。
#include "myapue.h" int main(void) { pid_t pid; if((pid = fork()) < 0) err_sys("fork error"); else if(pid == 0){ if((pid = fork()) < 0) err_sys("fork error"); else if(pid > 0)//first child exit(0); //second child sleep(2); printf("second child, parent pid = %ld\n", (long)getppid()); exit(0); } //parent if(waitpid(pid, NULL, 0) != pid) err_sys("waitpid error"); exit(0); }
(1)<190>
fork函数:子进程的返回值是0,父进程的返回值是新建子进程的进程ID。
waitpid函数:第一个参数为pid,pid>0:等待进程ID与pid相等的子进程。成功则返回终止进程的进程ID。
(2)调用两次fork,则父进程不用等待子进程终止,子进程也不用处于僵死状态直到父进程终止,因为父进程的子进程已经终止了。这样把子进程的任务交给子进程的子进程去做,两个任务互不影响。