while (...) {
int clnt_fd = accept(...);
if (-1 == clnt_fd) {
continue;
}
pid_t pid = fork();
if (-1 == pid)...;
else if (0 == pid) {
close(serv_fd);
while(1) {
int len = read();
if (0 == len) break;
write();
}
close(clnt_fd)
return;
}
else {close(clnt_fd)}
}
close(serv_fd)
这个if (-1 == clnt_fd) continue;的原因在于:
子进程结束的时候父进程收到SIGCHLD信号,此时如果父进程在accect处阻塞,由于accept不是可重入函数,因此父进程在响应信号中断accept会返回-1.
若不对-1加以判断,父进程将继续fork并且创建错误的子进程,若新的子进程也没有阻塞而是0=read()后退出,那么上述过程将陷入循环,导致程序执行出现问题.
上述过程使用wait()或者sigprocmask()都是不妥的
1.wait()阻塞主线程,使并发失去意义.
2.子进程退出时,应该注册SIGCHLD处理函数,以防止子进程成为僵尸进程.屏蔽掉SIGCHLD会产生僵尸进程
void handler(int) {
int status;
pid_t id = waitpid(-1, &status, WNOHANG);
if(WIFEXITED(status)) {...}
}
struct sigaction act;
act.sa_flag=0;
sigemptymask(&act.sa_mask);
act.sa_handler=handle;
关于fork
int main() {
int a{0};
printf("a: %d\na is %d ", a++, a++);
fork();
fork();
a = getpid();
printf("pid: %d, a: %d, &a: %p\n", getpid(), a, &a);
while(1) {}
return 0;
}
输出结果:
a: 1
a is 0 pid: 19201, a: 19201, &a: 0x7ffd8994b3a4
a is 0 pid: 19202, a: 19202, &a: 0x7ffd8994b3a4
a is 0 pid: 19204, a: 19204, &a: 0x7ffd8994b3a4
a is 0 pid: 19203, a: 19203, &a: 0x7ffd8994b3a4
原因:
1.printf要注意缓冲区,fork前主进程通过’\n’清理了部分缓冲区,但是留下了部分缓冲区,缓冲区内容就是a is 0,所以fork()时这部分被复制到了子进程的空间,随下一次请缓冲区被打印.
2.函数参数由右向左执行,所以留下的缓冲区是a++一次的,打印出来的是a++两次的
3.子进程内,a的值不同,但是&a的值即a地址相同,这是因为&a表示虚拟内存的地址,不同进程的a真正对应的物理内存地址是不同的