进程的创建以及进程间的通信
进程是一个运行着一个或多个线程的地址空间和这些线程所需要的系统资源;通过ps -ajx命令来打印当前所有进程;其中具体状态表示为:S表示睡眠,R表示可运行,D表示等待,T表示停止,Z表示僵尸进程;PID表示进程号,PPID表示父进程号;
一: PID ,PPID可以通过函数getpid(),getppid()获得, 下面是获取代码
1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <unistd.h> 4 5 int main() 6 { 7 pid_t myself_pid = getpid(); 8 pid_t parent_pid = getppid(); 9 10 printf("myself_pid is %d\n", myself_pid); 11 printf("parent_pid is %d\n", parent_pid); 12 13 return 0; 14 }
二: 创建一个新的进程
创建一个新的进程有三种方式:fork();system();exel ()族;
(1)system();
system()函数调用“/bin/sh -c command”执行特定的命令,阻塞当前的进程直到command执行完毕
下面是通过system()执行ls -a命令
1 #include <stdio.h> 2 3 int main() 4 { 5 //创建一个新进程 6 system("ls -a"); 7 printf("Over\n"); 8 9 10 return 0; 11 }
(2)exel族包含成员(execl,execlp,execle,execv,exevp,execve);
exel系列函数是替换型创建进程(子进程替换原有进程,和父进程做不同的事),只有PID保持不变(和调用exec的进程PID一样);
其部分原型如下:
int exelc(const char *path, const char * arg, ...);
int execlp(const char *file, const char * arg, ...);
int execv(const char *path, char * const argv[ ]);
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 5 int main() 6 { 7 int ret = 0; 8 char *argv[3] = {"ls", "-a", NULL}; 9 10 //创建新进程 11 ret = execv("/bin/ls", argv); 12 if(ret < 0) { 13 perror("execv"); 14 exit(EXIT_FAILURE); 15 } 16 17 printf("hello world\n"); //运行程序可以看到,没有输出 "hello world"(被替换) 18 19 return 0; 20 }
(3) fork();
一个现有进程可以调用fork()函数创建一个新的进程, 由fork创建的进程叫做子进程,fork函数调用一次但返回两次,两次返回的唯一区别是:
子进程中返回的是0值,二父进程中返回的是子进程的PID
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 5 int main() 6 { 7 pid_t pid = 0; 8 9 pid = fork(); 10 if(pid < 0) { 11 perror("fork"); 12 exit(EXIT_FAILURE); 13 } 14 15 //子进程 16 if(pid == 0) { 17 printf("this is child pid is: %d, ppid is: %d\n", getpid(), getppid());
18 19 } 20 //父进程 21 if(pid > 0) { 22 printf("this is parent pid is: %d, ppid is: %d\n", getpid(), getppid()); 23 } 24 25 printf("hello world\n");//可以看到"hello world"被打印了两次(父进程,子进程) 26 }
三:下面程序是父进程给文件加一把读锁,然后进入睡眠,子进程先睡 1秒钟,然后去验证文件锁,验证子进程看到的锁文件的进程是否是父进程
1 #include <stdio.h> 2 #include <fcntl.h> 3 #include <stdlib.h> 4 5 int main() 6 { 7 8 pid_t pid = fork(); 9 if(pid > 0) { 10 printf("this is father\n"); 11 12 //打开文件 13 int fd = 0; 14 fd = open("txt", O_RDWR); 15 if(fd < 0) { 16 perror("open"); 17 exit(EXIT_FAILURE); 18 } 19 20 int len = lseek(fd, 0, SEEK_END);//获取文件大小 21 lseek(fd, 0, SEEK_SET); 22 23 //父进程对文件加读锁 24 struct flock lock; 25 lock.l_type = F_RDLCK; 26 lock.l_whence = SEEK_SET; 27 lock.l_start = 0; 28 lock.l_len = len; 29 int ret = fcntl(fd, F_SETLK, &lock); 30 if(ret < 0) { 31 perror("child fcntl"); 32 exit(EXIT_FAILURE); 33 } 34 sleep(3); 35 exit(EXIT_SUCCESS); 36 } 37 38 //子进程 39 printf("child\n"); 40 sleep(1); 41 int fd = 0; 42 fd = open("txt", O_RDWR); 43 if(fd < 0) { 44 perror("open"); 45 exit(EXIT_FAILURE); 46 } 47 int len = lseek(fd, 0, SEEK_END); 48 lseek(fd, 0, SEEK_SET); 49 50 //子进程尝试去加写锁 51 struct flock lock; 52 lock.l_type = F_WRLCK; 53 lock.l_whence = SEEK_SET; 54 lock.l_start = 0; 55 lock.l_len = len; 56 int ret = fcntl(fd, F_GETLK, &lock); 57 if(ret < 0) { 58 perror("parent fcntl"); 59 exit(EXIT_FAILURE); 60 } 61 62 63 printf("parent is: %d\n", getppid()); 64 printf("lock.l_pid is: %d\n", lock.l_pid); 65 66 if(lock.l_type == F_RDLCK) { 67 printf("read lock\n"); 68 } 69 printf("lock.l_whence is: %d\n", lock.l_whence); 70 printf("lock.l_len is: %d\n", lock.l_len); 71 72 close(fd); 73 exit(EXIT_SUCCESS); 74 }