/*
* 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,则父进程不用等待子进程终止,子进程也不用处于僵死状态直到父进程终止,因为父进程的子进程已经终止了。这样把子进程的任务交给子进程的子进程去做,两个任务互不影响。