Process API Homework CC=gcc GCCFLAGS= -g -Wall TARGET = $(word  1,$(MAKECMDGOALS) )  SRC=$(word  1,$(MAKECMDGOALS) ) .c $(TARGET) :$(SRC)     $(CC)  $(GCCFLAGS)  $(SRC)  -o $(TARGET)  
 
#include  <stdio.h>  #include  <unistd.h>  #include  <stdlib.h>  #include  <sys/types.h>  int  main ()  {    int  x = 1 ;     printf ("%d\n" , x);     x = 2 ;     pid_t  rc = fork();     if  (rc < 0 ) {         fprintf (stderr , "fork failed\n" );         exit (1 );     }     else  if  (rc == 0 ) {         printf ("fork %d\n" , x);         x = 3 ;         printf ("fork %d\n" , x);     }     else  {         wait(NULL );         printf ("%d\n" , x);     } } 
grxer@grxer /m/h/S/O/o/cpu-api> make 1 gcc -g -Wall 1.c -o 1 1.c: In function ‘main’: 1.c:20:9: warning: implicit declaration of function ‘wait’ [-Wimplicit-function-declaration]          wait(NULL);          ^ grxer@grxer /m/h/S/O/o/cpu-api> ./1 1 fork 2 fork 3 2 
子进程和父进程变量没有任何关系
 
 
#include  <sys/types.h>  #include  <sys/stat.h>  #include  <fcntl.h>  #include  <stdio.h>  #include  <stdlib.h>  #include  <string.h>  #include  <assert.h>  int  main ()  {    int  fd = open("./flag" ,O_RDWR|O_APPEND);     assert(-1  != fd);     int  pid = fork();     if  (pid < 0 ) {         fprintf (stderr , "fork failed\n" );         exit (1 );     }     else  if  (0 ==pid){         char  buf[100 ] = { 0  };         read(fd, buf, sizeof (char ) * 10 );         printf ("child:%s\n" , buf);         memcpy (buf, "child" , strlen ("child" ));         for  (size_t  i = 0 ; i < 10 ; i++)         {             int  err = write(fd, buf, strlen (buf) * sizeof (char ));             assert(err);         }              }     else  {         char  buf[100 ] = { 0  };         read(fd, buf, sizeof (char ) * 10 );         printf ("parent:%s\n" , buf);                  memcpy (buf, "parent" , strlen ("parent" ));         for  (size_t  i = 0 ; i < 10 ; i++)         {             int  err = write(fd, buf, strlen (buf) * sizeof (char ));             assert(err);         }         wait(NULL );     } } 
grxer@grxer /m/h/S/O/o/cpu-api> cat flag 1111111111xxxxxxxxxxx grxer@grxer /m/h/S/O/o/cpu-api> ./2 parent:1111111111 child:xxxxxxxxxx grxer@grxer /m/h/S/O/o/cpu-api> cat flag 1111111111xxxxxxxxxxx parent1111parent1111childxxxxxchildxxxxxparent1111parent1111childxxxxxchildxxxxxparent1111parent1111childxxxxxparent1111parent1111childxxxxxchildxxxxxparent1111parent1111childxxxxxchildxxxxxchildxxxxx⏎                   
可以看出父子是共享文件描述符的,父进程读后文件的读写位置往后移到了xxxxx,可以用    lseek(fd, 0, SEEK_SET);把他移到开头
并发的写入由于操作系统调度顺序问题,写入顺序是随机的,竞争关系的他们并不能同时使用fd,操作系统应该加了一些锁
 
 
#include  <unistd.h>  #include  <stdio.h>  #include  <stdlib.h>  int  main ()  {    int  x = 10 ;     int  pid = vfork();     if  (pid < 0 ) {         fprintf (stderr , "fork failed\n" );         exit (1 );     }     else  if  (0  == pid) {         x = 66 ;         printf ("hello  " );         exit (0 );     }     else  {         printf ("world-----" );         printf ("%d" ,x);     } } 
grxer@grxer /m/h/S/O/o/cpu-api> make 3 gcc -g -Wall 3.c -o 3 grxer@grxer /m/h/S/O/o/cpu-api> ./3 hello  world-----66⏎     
可以调用vfork函数,和fork函数的区别就是他会阻塞父进程,直到子进程调用exec或exit才恢复调度可能,在此之前和父进程共享所以内存包括栈!可以看的x已经被修改
 
 
#include  <stdio.h>  #include  <stdlib.h>  #include  <unistd.h>  int  main (int  argc, char * argv[], char * envp[])  {    int  pid = fork();     char * cmd = "/bin/ls" ;     char * name = "ls" ;     char * arg[] = { "ls" , "-a" , "-l" , "-h" , NULL  };     if  (pid < 0 ) {         perror("error" );         exit (1 );     }     else  if  (pid == 0 ) {                  execlp(name, "ls" ,"-a" , "-l" , "-h" ,NULL );                                         }     else  {     } } 
以exec为前缀
l(list)使用参数地址列表,以空指针结束标志execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);。第二个参数ls没有太大意义,如果要给ls传参必须写上这个字符串, 
v(vector) 以 NULL结尾字符串数组的指针作参数 
p(path) PATH环境变量指定的目录搜索可执行文件,可以不用写路径 
e(environment) 可以传存有环境变量envp字符串地址的指针数组的地址,无后缀e的话使用当前进程环境变量 
 
 
 
#include  <unistd.h>  #include  <stdio.h>  #include  <stdlib.h>  #include  <sys/types.h>  #include  <sys/wait.h>  #include  <assert.h>  int  main ()  {    int  pid = vfork();     if  (pid < 0 ) {         fprintf (stderr , "fork failed\n" );         exit (1 );     }     else  if  (0  == pid) {         puts ("gr" );         int  rs = wait(NULL );         printf ("%d\n" , rs);         exit (0 );     }     else  {         int  rs = wait(NULL );         assert(pid == rs);     } } 
rxer@grxer /m/h/S/O/o/cpu-api> make 5 gcc -g -Wall 5.c -o 5 grxer@grxer /m/h/S/O/o/cpu-api> ./5 gr -1 
父进程wait成功等待了返回子进程id,否则-1,子进程返回-1
 
 
其他更精细的事情,比如非阻塞等待:希望子进程退出能够被我父进程检测到,同时我又不希望我父进程处于阻塞等待waitpid(pid,NULL,WNOHANG)
 
 
#include  <unistd.h>  #include  <stdio.h>  #include  <stdlib.h>  #include  <sys/types.h>  #include  <sys/wait.h>  #include  <assert.h>  int  main ()  {    int  pid = fork();     if  (pid < 0 ) {         fprintf (stderr , "fork failed\n" );         exit (1 );     }     else  if  (0  == pid) {         printf ("child hello" );         close(STDOUT_FILENO);         printf ("grxer" );         exit (0 );     }     else  {         printf ("parent : hello" );         wait(NULL );         printf (" world\n" );     } } 
grxer@grxer /m/h/S/O/o/cpu-api> make 7 gcc -g -Wall 7.c -o 7 grxer@grxer /m/h/S/O/o/cpu-api> ./7 parent : hello world 
没有输出的同时可以看出子进程继承了文件描述符,但是继承过后就是私有的了,不会影响父进程
 
 
#include  <stdio.h>  #include  <unistd.h>  #include  <stdlib.h>  #include  <sys/types.h>  #include  <string.h>  #include  <assert.h>  #include  <sys/wait.h>  int  main ()  {    pid_t  pid[2 ];     int  pidfd[2 ];     int  res = pipe(pidfd);     assert(0  == res);     pid[0 ] = fork();     if  (pid[0 ] < 0 ) {         perror("fork1 fail" );         exit (-1 );     }     else  if  (0  == pid[0 ]) {         close(pidfd[0 ]);         assert(dup2(pidfd[1 ], STDOUT_FILENO) == STDOUT_FILENO);         printf ("i am from pid[0]" );         close(pidfd[1 ]);     }     else  {         pid[1 ] = fork();         if  (pid[1 ] < 0 ) {             perror("fork2 fail" );             exit (-2 );         }         else  if  (0  == pid[1 ]) {             char  buf[30 ] = {0 };             close(pidfd[1 ]);             assert(dup2(pidfd[0 ], STDIN_FILENO) == STDIN_FILENO);             read(STDIN_FILENO,buf,30 );             printf ("pid[1]:where are you from??\n %s" ,buf);             close(pidfd[0 ]);         }         else  {             waitpid(pid[0 ], NULL , 0 );             waitpid(pid[1 ], NULL , 0 );         }     } } 
grxer@grxer /m/h/S/O/o/cpu-api> make 8 gcc -g -Wall 8.c -o 8 grxer@grxer /m/h/S/O/o/cpu-api> ./8 pid[1]:where are you from??  i am from pid[0]⏎       
#include  <unistd.h>  int  pipe (int  pipefd[2 ]) ;成功返回0  失败返回-1  
管道:半双工通道,只允许数据在一个方向上传输的通道。发送方和接收方不能同时发送数据,只能轮流进行发送和接收。用于进程间通信
pipe函数创建一个管道,pipefd返回管道两端的文件描述符,pipefd[0]是读端,pipefd[1]是写端
管道可以理解为进程共用的内核空间里的一块内存来充当虚拟文件
#include  <unistd.h>  int  dup (int  oldfd) ;int  dup2 (int  oldfd, int  newfd) ;On success, these system calls return  the new descriptor.  On error, -1  is returned, and errno is set  appropriately. 
dup函数创建一个oldfd文件描述符的副本(而且是动态的副本,本质上是一个,只不过起了不同名字),不过不共享文件描述符标志,返回新文件描述符是取系统当前可用的最小整数值
dup2 和dup功能一样,不过它可以用newfd指定返回的新文件描述符号,如果newfd是一个已经打开的描述符,会把他先关闭