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;
}
浙公网安备 33010602011771号