题目描述:
算法设计:
多进程:
这里主要是利用系统调用fork:
- fork是Linux下创建进程的一个系统调用
调用fork的进程为主进程,一次调用会产生一个子进程。 - fork的特点:一次调用两次返回:
主进程和子进程的差异就从fork这条语句开始,fork给调用他的主进程的返回值是子进程的PID (若成功),给子进程的返回值是0,故可由此判断当前进程是子进程还是父进程,如:
int pid = fork();
if(pid==0){
//说明是子进程,这里写子进程的相关操作
}
else{
//说明是父进程,这里写父进程的相关操作
}
如何创建多个子进程?
错误的方法:
for(int i=0;i<10:i++)
fork();
这显然不正确,因为不仅有父进程可以执行fork()语句,子进程也能执行,这就会导致实际创建的进程比预期的要多,因为有类似子进程的子进程存在。
避免这个问题也很简单,只在父进程执行fork()就行了,区分父子进程的方法上面已经给出。
我的具体实现代码:
int childpid[10];//用来保存所有进程的PID,0号是主进程
childpid[0]=getpid();//012分别是父进程和两个子进程的pid
for(int i=1;i<=2;i++){
int pid=fork();
if(pid!=0)
childpid[i] =pid;
else{
childpid[i] =getpid();
break;
}
}
信号机制:
这里需要用到几个函数:
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,fun_chid);
signal(SIGUSR2,fun_chid);
kill(childpid[1],SIGUSR1);
kill(childpid[2],SIGUSR2);
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式
使用signal()函数处理时,只需指出要处理的信号和处理函数即可。
原型:/signal-handler/* signal(int sig, /signal-handler/* handler);
参数:
sig:要设置信号处理函数的信号。它可以是实现定义值或预定义的宏:
handler:信号处理函数。这必须是下列之一:
SIG_DFL 宏。信号处理函数被设为默认信号处理函数。
SIG_IGN 宏。忽略信号。
指向函数指针。
返回值
成功时为先前的信号处理函数,失败时为 SIG_ERR (某些实现上能禁用设置信号处理函数)。
信号:
SIGINT:ctrl+c 终止信号
SIGQUIT:ctrl+\ 终止信号
SIGTSTP:ctrl+z 暂停信号
SIGALRM:闹钟信号 收到此信号后定时结束,结束进程
SIGCHLD:子进程状态改变,父进程收到信号
SIGKILL:杀死信号
用户进程对信号的响应方式:
忽略信号
捕捉信号
执行缺省操作
相关函数:
int kill(pid_t pid, int sig);
功能:信号发送
参数:pid:指定进程
sig:要发送的信号
返回值:成功 0;失败 -1
管道通信:
int flg,fd[2];
flg = pipe(fd); //创建管道
if (flg == -1)
perror("pipe error");
write(fd[1],child,strlen(child)+1);
read(fd[0],msg,sizeof(msg))
-
pipe函数的原型:
int pipe (int fd[2]); //成功返回0,出错返回-1
fd参数是数组/指针,可以带回两个值(文件描述符),
fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。 -
pipe通信(父子进程间)的流程:
1.父进程创建管道,得到两个件描述符指向管道的两端
2.发进程关闭fd[1](读端),利用write()向管道写入
3.收进程关闭fd[0](写端),利用read()从管道读出
实现代码:
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int childpid[10]={-1,-1,-1,-1},status=999;
void fun_pare(int sig)//父进程响应Ctrl C 信号函数
{
kill(childpid[1],SIGUSR1);
kill(childpid[2],SIGUSR2);
}
void fun_chid(int sig)//子进程1响应信号函数
{
if(sig==SIGUSR1)
printf("\nChild Process 1 is killed by parent!\n");
if(sig==SIGUSR2)
printf("\nChild Process 2 is killed by parent!\n");
exit(822);//默认正常退出返回0
}
int main(){
int ret,fd[2];
ret = pipe(fd); //创建管道
if (ret == -1)
perror("pipe error");
childpid[0]=getpid();//012分别是父进程和两个子进程的pid
for(int i=1;i<=2;i++){
int pid=fork();
if(pid!=0)
childpid[i] =pid;
else{
childpid[i] =getpid();
break;
}
}
if(getpid()==childpid[0]){//父进程
printf("我是父进程,PID:%d PPID:%d\n",getpid(),getppid());
printf("\t子进程1是:PID:%d\n",childpid[1]);
printf("\t子进程2是:PID:%d\n",childpid[2]);
signal(SIGINT,fun_pare);//发出中断信号
int child_num = 2;//子进程个数
while(child_num --){
int t = wait(&status);//等待两个子进程结束
printf("一个进程结束了,他的 PID:%d 返回码 :%d\n",t,status);
}
printf("Parent process is killed!\n");//两个子进程都结束后主进程才可以结束
exit(822);//默认正常退出返回0
}
else{//否则是子进程
signal(SIGINT,SIG_IGN);
signal(SIGUSR1,fun_chid);
signal(SIGUSR2,fun_chid);
}
if(getpid()==childpid[1]){//子进程1
int i=0;
close(fd[0]);
char child[100]="I send message x times !\0";
while(++i)
{
child[15] = '0' + i;
write(fd[1],child,strlen(child)+1);
sleep(1);
}
}
if(getpid()==childpid[2]){//子进程2
close(fd[1]);
char msg[100];
while(1)
{
if(read(fd[0],msg,sizeof(msg)))
printf("%s\n",msg);
}
}
return 0;
}