1 Resource Duplication Across Forks
- 子进程是父进程的复制,在
fork
瞬间复制所有信息- 复制父进程的代码
- 复制父进程的状态,包含全部的内存空间,比如变量
/*shared_variable.c*/
int main(int argc, char * argv[]){
int status;
pid_t cpid, pid;
int i=0;
while(1){ //loop and fork children
cpid = fork();
if( cpid == 0 ){
/* CHILD */
pid = getpid();
printf("Child: %d: i:%d\n", pid, i);
//set i in child to something differnt
i *= 3;
printf("Child: %d: i:%d\n", pid, i);
_exit(0); //NO FORK BOMB!!!
}else if ( cpid > 0){
/* PARENT */
//wait for child
wait(&status);
//print i after waiting
printf("Parent: i:%d\n", i);
i++;
if (i > 5){
break; //break loop after 5 iterations
}
}else{
/* ERROR */
perror("fork");
return 1;
}
//pretty print
printf("--------------------\n");
}
return 0;
}
>./shared_variables
Child: 3833: i:0
Child: 3833: i:0
Parent: i:0
--------------------
Child: 3834: i:1
Child: 3834: i:3
Parent: i:1
--------------------
Child: 3835: i:2
Child: 3835: i:6
Parent: i:2
--------------------
Child: 3836: i:3
Child: 3836: i:9
Parent: i:3
--------------------
Child: 3837: i:4
Child: 3837: i:12
Parent: i:4
--------------------
Child: 3838: i:5
Child: 3838: i:15
Parent: i:5
1.1 File Descriptor’s across Forks
- 子复制父的文件描述符
- 父子同时对文件进行读写,共享
offset
/*shared_file.c*/
int main(int argc, char * argv[]){
int fd, status;
pid_t cpid;
char c;
if ( argc < 2){
fprintf(stderr, "ERROR: Require path\n");
return 1;
}
//shared between all children and parent
if( (fd = open(argv[1], O_RDONLY)) < 0){
perror("open");
return 1;
}
while (1){
cpid = fork();
if( cpid == 0 ){
/* CHILD */
//try and read 1 byte from file
if( read(fd, &c, 1) > 0){
printf("c: %c\n", c); // print the char
_exit(0); //exit with status 0 on sucess read
}else{
//no more to read
_exit(1); //exit with status 1 on failed read
}
}else if ( cpid > 0){
/* PARENT */
//wait for child to read first
wait(&status);
//if exit status 1, break the loop, no more to read
if( WEXITSTATUS(status) ){
break;
}
//now parent reads a byte
if( read(fd, &c, 1) > 0){
printf("p: %c\n", c); // print the char
}
}else{
/* ERROR */
perror("fork");
return 1;
}
}
//done reading the file
close(fd);
return 0;
}
2 Inter-Process Communication and Pipes
- pipeline是进程之间外部通讯(一个进程,接收另一个进程执行的结果),pipe是进程内部通讯
int main(int argc, char * argv[]){
//print hello world through a pipe!
char hello[] = "Hello World!\n";
char c;
int pfd[2]; //pfd[0] reading end of pipe
//pfd[1] writing end of pipe
//open the pipe
if( pipe(pfd) < 0){
perror("pipe");
return 1;
}
//write hello world to pipe
write(pfd[1], hello, strlen(hello));
//close write end of pipe
close(pfd[1]);
//read hello world from pipe, write to stdout
while( read(pfd[0], &c, 1)){
write(1, &c, 1);
}
//close the read end of the pipe
close(pfd[0]);
return 0;
}
2.2 Pipes Bursting! and Blocking!
- O.S. and the C standard library provides some amount of buffering on reads and writes. (C库和操作系统读写都有buffer)
- pipe就是kernel中的buffer
- when the pipe is full, the write will block.
- fcntl() or file descriptor control.通过fd来改变buffer的属性
fcntl(pfd[1], F_SETFL, O_NONBLOCK);
/*pipe_block.c*/
int main(int argc, char * argv[]){
char c = 'A';
int i;
int pfd[2]; //pfd[0] reading end of pipe
//pdf[1] writing end of pipe
//open the pipe
if( pipe(pfd) < 0){
perror("pipe");
return 1;
}
//write A's to pipe until it's full
i = 0;
while( write(pfd[1], &c, 1) > 0){
printf("%d\n",i);
i++;
}
perror("write");
//close write end of pipe
close(pfd[1]);
//read from pipe?!?
while( read(pfd[0], &c, 1)){
write(1, &c, 1);
}
close(pfd[0]);
return 0;
}
2.3 Inter Process Pipes
1.子进程复制父进程,所以pipe对应的文件描述符也会被复制
/*pipe_hello_to_child.c*/
int main(int argc, char * argv[]){
//print hello world through a pipe! To child!
char hello[] = "Hello World!\n";
char c;
int pfd[2]; //pfd[0] reading end of pipe
//pfd[1] writing end of pipe
pid_t cpid;
int status;
//open a pipe, pfd[0] for reading, pfd[1] for writing
if ( pipe(pfd) < 0){
perror("pipe");
return 1;
}
cpid = fork();
if( cpid == 0 ){
/* CHILD */
//close the writing end in child
close(pfd[1]);
//try and read 1 byte from pipe, write byte stdout
while( read(pfd[0], &c, 1) > 0){
write(1, &c,1);
}
//close pipe
close(pfd[0]);
_exit(0);
}else if ( cpid > 0){
/* PARENT */
//close reading end in parent
close(pfd[0]);
//write hello world to pipe
write(pfd[1], hello, strlen(hello));
//close the pipe
close(pfd[1]);
//wait for child
wait(&status);
}else{
/* ERROR */
perror("fork");
return 1;
}
return 0;
}
3 Duplicating File Descriptor and Pipelines
1.pipe 是通过文件描述符来实现进程内部通讯
2.pipline则是通过stdout和stdin来进程进程外部通讯
3.1 Duplicating a File Descriptor
int dup2(int filedes, int filedes2);
- duplicate the file descriptor fildes onto the file descriptor filedes2
- read and write from fildes2 now, it would be the same as reading and writing from filedes
/*hello_dup.c*/
int main(int argc, char * argv[]){
//print hello world to a file with dup
int fd;
//check args
if ( argc < 2){
fprintf(stderr, "ERROR: Require destination path\n");
return 1;
}
//open destination file
if( (fd = open(argv[1], O_WRONLY | O_TRUNC | O_CREAT , 0644)) < 0){
perror("open");
return 1;
}
//close standard out
close(1);
//duplicate fd to stdout
dup2(fd, 1);
//print to stdout, which is now duplicated to fd
printf("Hello World!\n");
return 0;
}
3.2 Setting up a pipeline
/*pipe_dup.c*/
int main(int argc, char * argv[]){
int status;
int pfd[2];
pid_t cpid;
char c;
//open a pipe, pfd[0] for reading, pfd[1] for writing
if ( pipe(pfd) < 0){
perror("pipe");
return 1;
}
//Setup a pipe between child 1 and child 2, like:
// parent | child
cpid = fork();
if( cpid == 0 ){
/* CHILD 1*/
//close stdin
close(0);
//duplicate reading end to stdin
dup2(pfd[0], 0);
//close the writing end
close(pfd[1]);
//try and read 1 byte from stding and write stdout
while( read(0, &c, 1) > 0){ //stdin now pipe!
write(1, &c,1); //this is still stdout
}
exit(0);
} else if ( cpid > 0){
/* PARENT */
//close stdout
close(1);
//duplicate writing end to stdout
dup2(pfd[1], 1);
//close reading end
close(pfd[0]);
//read and read 1 byte from stdin, write byte to pipe
while( read(0,&c,1) > 0){
write(1, &c, 1);
}
//close the pipe and stdout
close(pfd[1]);
close(1);
//wait for child
wait(&status);
}else{
/* ERROR */
perror("fork");
return 1;
}
return 0;
}