#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "apue.h"
static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;
static void
sig_usr(int signo)
{
sigflag = 1;
}
void
TELL_WAIT(void)
{
if(signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("signal(SIGUSR1)");
if(signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("signal(SIGUSR2)");
//防止其他函数产生SIGUSR1, SIGUSR2干扰
sigemptyset(&newmask);
sigemptyset(&zeromask);
sigaddset(&newmask, SIGUSR1);
sigaddset(&newmask, SIGUSR2);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
err_sys("sigprocmask(SIG_BLOCK)");
}
void
TELL_PARENT(pid_t pid)
{
kill(pid, SIGUSR1);
}
void
WAIT_PARENT(void)
{
if(sigflag == 0)
sigsuspend(&zeromask);
sigflag = 0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("sigprocmask(SIG_SETMASK)");
}
void
TELL_CHILD(pid_t pid)
{
kill(pid, SIGUSR2);
}
void
WAIT_CHILD(void)
{
if(sigflag == 0)
sigsuspend(&zeromask);
sigflag = 0;
if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err_sys("sigprocmask(SIG_SETMASK)");
}
int
main(void)
{
FILE *fp;
pid_t pid;
int count = 0;
int i = 0;
if((fp = fopen("tmp", "wr")) == NULL)
err_sys("fopen");
fprintf(fp, "By main process : %d, count = %d\n", getpid(), count);
fflush(NULL); //全缓冲,为了立即得到输出,冲洗
TELL_WAIT();
if((pid = fork()) < 0)
err_sys("fork");
else if(pid == 0) {
count++;
fprintf(fp, "By child process : %d, count = %d\n", getpid(), count);
fflush(NULL);
sleep(1);
TELL_PARENT(getppid());
WAIT_PARENT();
while(i++ < 4) {
count += 2;
fprintf(fp, "By child process : %d, count = %d\n", getpid(), count);
fflush(NULL);
sleep(1);
TELL_PARENT(getppid());
WAIT_PARENT();
}
TELL_PARENT(getppid()); //子进程先退出while,防止父进程一直阻塞
_exit(127);
} else {
while(i++ < 5) {
WAIT_CHILD();
count += 2;
fprintf(fp, "By parent process : %d, count = %d\n", getpid(), count);
fflush(NULL);
sleep(1);
TELL_CHILD(pid);
}
wait(NULL); //
}
fclose(fp);
printf("over\n");
return 0;
}
vim复制全文:
ggyG,:1,$y
文件指针和文件描述符的区别:
文件描述符就是open文件时产生的一个整数,直到一个索引作用,它用于UNIX系统中,用于标识文件。
文件指针是指向一个FILE的结构体,这个结构体里有一个元素就是文件描述符。它用于ANSI C标准的IO库调用中,用于标识文件。
既然FILE中包含文件描述符元素,可以用fopen()直接获取指针fp,然后使用fp获得fp中所包含文件描述符fd的信息。
文件描述符应该是唯一的,但文件指针(值)却不是唯一的,但指向的对象却应该是唯一的。
FILE *中除了包含了fd信息,还包含了IO缓冲,所以可以理解为FILE是对fd的墙头,是C标准形式,所以FILE *比fd更适合跨平台,应该多用fopen在,少用open。
C语言文件指针与文件描述符之间可以相互转换:
int fileno(FILE *stream);
FILE *fdopen(int fd, const char *mode);
fork函数需要注意的地方:
父子进程可以通过共享内存的方法来共享变量,用文件也可以(读写就行了)。因为并不是多线程,也没有采取共享变量的方法(PS, 还没学到那儿),所以在上面代码变量count并不是父子进程共享的,我只能自己模拟(count += 2),另外,对于文件指针fp这个变量,在父子进程中并不会互相干扰,但却指向同一个FILE结构体。而结构体包含了文件描述符的信息。
起初想vfork函数实现父子进程共享变量count,后来思考,这样就不能实现父子进程交替写操作了,因为vfork总是子进程先运行,直到子进程调用exit或者exec函数。为了避免僵尸进程,父进程wait,注意此时子进程先退出while循环,而父进程还在等信号,所以子进程要处理好后事(TELL_PARENT),避免父进程一直挂起。
因为用的是标准IO,在不涉及终端设备时,流是全缓冲的,所以用了fflush。