linux C 多进程编程
linux 多进程编程有如下要点
第一:首当其冲的是进程状态,我把本地的ubuntu进程截图了一份,请看:
进程的状态如下:
R:running,运行状态。
S:可中断的睡眠状态。
D:不可中断的睡眠状态。
T:暂停状态。
Z:僵尸状态。
<:高优先级别
N:低优先级别
+:前台进程
第二,创建进程
函数定义:pid_t fork();
成功时,返回进程id,失败时返回-1. 参考例子如下:
#include <stdio.h> #include <unistd.h> int main() { pid_t pid=fork(); if(pid==0) { fputs("Hi i am child proc...",stdout); } else{ fputs("Child proc id is: %d \n ",stdout); sleep(30); } if(pid==0) { puts("End child process"); } else{ puts("End parent process"); } return 0; }
当pid==0时,是子进程代码运行区域。其他则是父进程运行区域。由于父进程没有接收到子进程的返回值,这样子进程会转换为僵尸进程。
第三 僵尸进程的处理
1)wait 方法:wait方法会一直阻塞当前进程运行,直到有当前进程的子进程结束,wait方法会返回。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { int status; pid_t id=fork(); if(id==0) { return 4; } else{ printf("child proc id is: %d \n",id); wait(&status); if(WIFEXITED(status)) { printf("THe child process return normal:%d \n ",WEXITSTATUS(status)); } sleep(30); } if(id==0) { fputs("The child process ends..\n",stdout); } else{ fputs("The parent process ends..\n",stdout); } return 0; }
2)waitpid 方法:该方法不会阻塞当前进程。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); int status; if(pid==0) { puts("The child process running...."); sleep(9); exit(24); } else{ while(!waitpid(pid,&status,WNOHANG)) { sleep(3); puts("3 seconds..."); } if(WIFEXITED(status)) { printf("Child sent is: %d \n",WEXITSTATUS(status)); } } return 0; }
3)使用信号处理机制,核心在于signal 方法
signal 方法第一个参数为事件名称。第二个参数为第一个参数事件发生时,需要调用的函数。
事件主要有三个:
SIGCHLD,当前进程的子进程结束时会自动发出这个信号。
SIGINT,当用户按ctrl c时,系统会发出这个信号。
SIGALRM.系统的alarm函数运行到期后,会发出这个信号。
例子如下:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void timeout(int sig) { printf("time out is: %d \n",sig); if(sig==SIGALRM) { puts("time out...."); } alarm(2); } void keycontrol(int sig) { printf("keycontrol is: %d \n",sig); if(sig==SIGINT) { puts("Ctrl c pressed.."); } } int main() { signal(SIGINT,keycontrol); signal(SIGALRM,timeout); alarm(3); puts("hahahahahah"); int i; for(i=0;i<3;i++) { puts("wait....."); sleep(30); } return 0; }
4)sigaction函数,这个函数是跨平台的。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void timeout(int sig) { if(sig==SIGALRM) { puts("time out...."); } alarm(2); } int main() { int i=0; struct sigaction sig; sig.sa_handler=timeout; sig.sa_flags=0; sigemptyset(&sig.sa_mask); sigaction(SIGALRM,&sig,0); alarm(2); for(i=0;i<100;i++) { sleep(100); puts("wait...."); } return 0; }
这里结构体sigaction的sa_flags=0,sa_mask 都用0即可。sa_handler用来指定处理函数。
第四:进程通信
由于进程是独立的内存结构,因此进程间不存在共享变量,所以使用管道,管道是内核所有的。见如下例子:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <wait.h> void readProc(int sig) { if(sig==SIGCHLD) { int status; waitpid(-1,&status,WNOHANG); if(WIFEXITED(status)) { printf("received from child is: %d \n",WEXITSTATUS(status)); sleep(30); } } } int main() { struct sigaction sig; sig.sa_handler=readProc; sigemptyset(&sig.sa_mask); sig.sa_flags=0; sigaction(SIGCHLD,&sig,0); int fd1[2],fd2[2]; char str1[] = "who are you"; char str2[] = "I am lucy"; char buf[50]; pipe(fd1); pipe(fd2); pid_t id; id = fork(); if(id==0) { write(fd1[1],str1,sizeof(str1)); read(fd2[0],buf,50); printf("child proc recived from parent is: %s \n",buf); return 88; }else{ read(fd1[0],buf,50); write(fd2[1],str2,sizeof(str2)); printf("parent proc recived from child is: %s \n",buf); sleep(40); } return 0; }