《Linux》Linux进程通信示例代码及其分析

/*运行时屏幕上交替出现子进程与父进程各打印出的若干条信息*/
/*注意观察出现的交替情况每次可能会不一样,注意观察命令提示符出现的位置*/
#include <stdio.h>
int main()
{ 
	int i; 
	if ( fork() == 0 ) /*创建新的子进程,并判断是否是子进程*/
	{ 
		/* 子进程程序 */ 
		for ( i = 0; i < 1000; i++ ) 
		printf("This is child process %d \n",i); 
	} 
	else 
	{ 
		/* 父进程程序*/ 
		for ( i = 0; i < 1000; i++ ) 
		printf("This is parent process %d \n",i); 
	} 
} 

运行结果

/*使用exec系列函数使子进程执行新的目标程序*/
#include <stdio.h> /*头文件*/
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main() 
{	
	pid_t pid; /*进程标识变量*/
	char *para[]={"ls","-a",NULL}; /*定义参数组,为execv所使用*/
	if((pid=fork())<0) /*创建新的子进程*/
	{
		perror("fork"); /*错误处理*/
	    exit(0);//正常退出
	}
	if(pid==0) /*子进程*/
	{
		printf("\我是子进程1号\n");
		/*excel(参数1,参数2,...,参数n),先是执行参数1中字符串所代表的路径,接下的参数代表执行该文件时候传递去的argv(n),然后最后一个参数使用空指针结束,如果执行成功,函数不会返回,如果执行失败,函数就会反回一个负数*/
        if(execl("/bin/ls","ls","-l",(char *)0)==-1) 
		{
			perror("execl");
			exit(0);
		}
        printf("\n我执行了ecexl函数\n");
	}
	if((pid=fork())<0) /*创建新的子进程*/
	{
		perror("fork");//用于将错误原因输出,先输出"fork:",然后后面将错误原因输出
	 	exit(0);
	}
	if(pid==0)
	{
		printf("\n我是子进程2号\n");
		/*很明显,接下来执行了para数组之中的字符串*/
        if(execv("/bin/ls",para)==-1) /*转去执行ls -a命令并判断是否出错*/
		{
			perror("execv");
			exit(0);
		}
        printf("\n我执行了para数组里面的命令\n");
	}
	return;
}

运行结果

/*实现进程的软中断通信*/
/*按Ctrl+c键,可发送SIGINT信号给当前进程*/
/*使用系统调用fork()创建两个子程序,再用系统调用signal()注册父进程和子进程分别对待从键盘上来的中断信号(SIGINT信号)的行为;当有中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程收到信号后分别输出
"Child Processll is Killed by Parent!"
"Child Processl2 is Killed by Parent!"
进程等待两个子进程终止后,输出如下的信息后终止:
"Parent process is Killed!"
*/
#include<stdio.h>
#include<signal.h>
#include <stdlib.h>
int wait_mark;//很明显,从变量名上可以知道这是一个等待标志
void waiting()//很明显,这是一个等待函数,直到wait_mark!=1的时候,就退出无限循环
{
	while(wait_mark==1);
}
void  stop()//很明显,这时候不清楚这个函数是用来干嘛的
{
	wait_mark=0;
}       
int main()
{
	int p1,p2;//很明显,这是两个信号量
	while((p1=fork())==-1);//创建子进程1如出错会进入循环
	if(p1==0)//如果成功创建子进程,并且执行子进程
	{
		printf("I am child process 1 ,I am live!\n");
		wait_mark=1;//将等待标志置为1,要干嘛呢?
        signal(SIGINT,SIG_IGN);/*SIG_ING代表忽略SIFINT信号,signal(参数1,参数2),参数1是我们要处理的信号,参数2是我们的处理方式(有系统默认,忽略,捕获三种),SIGINT信号通常是用CTRL+C用来发给所有的ForeGround Group的进程的*/
        signal(16,stop);//注册16号信号发生后的处理函数为stop,将wait_mark置为0
        waiting();//然后发现wait_mark注册时候就能够使得waiting函数无限执行下去了
        printf("Child Process 1 is Killed by Parent!\n");/*一般fork()之后,都是先执行父进程的,一旦发送了信号16,那么就推出了waiting()。然后执行exit()也就是杀掉了子进程了*/
        exit(0);//0代表正常退出程序
	}
	else//如果是父进程的,就执行下面这个分支了
	{
        while((p2=fork())==-1);//创建子进程2如出错会进入循环
        if(p2==0)
        {
	        printf("I am child process 2 ,I am live!\n");
	        wait_mark=1;
            signal(SIGINT,SIG_IGN);/*SIG_ING代表忽略SIFINT信号,signal(参数1,参数2),参数1是我们要处理的信号,参数2是我们的处理方式(有系统默认,忽略,捕获三种),SIGINT信号通常是用CTRL+C用来发给所有的ForeGround Group的进程的*/
            signal(17,stop);//注册17号信号发生后的处理函数为stop
            waiting();//进入了无限的等待之中
            printf("Child Process 2 is Killed by Parent!\n");
            exit(0);
         }
         else//执行父进程2
         {
            wait_mark=1;
            signal(SIGINT,stop);//注册SIGINT信号发生后的处理函数
            waiting();//进入了无限的等待之中
            kill(p1,16);//发送16号信号给p1,很明显16号信号是子进程1的signal函数定义的信号
            kill(p2,17);//发送17号信号给p1,很明显17号信号是子进程2的signal函数定义的信号
            wait(0);//在没有唤醒的情况下,这个父进程2将会处于等待状态
            wait(0);
            printf("Parent Process is Killed!\n");
            exit(0);
          }
	}
}
/*使用fork()创建子进程之后,先执行子进程1,然后子进程1进入了循环,这时候执行父进程1,父进程1又使用了fork(),创建了子进程2,执行子进程2,子进程2进入循环,然后执行父进程2,父进程2调用kill()终结了子进程1和子进程2的循环状态*/

运行结果

/*sigaction系统调用的使用方法。sigaction函数的功能是检查或修改与制定信号相关联的处理动作,可以完全代替signal函数*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
    int iSeq=g_iSeq++;
    printf("%d Enter SignHandlerNew,signo:%d.\n",iSeq,iSignNo);
    sleep(3);/*睡眠3秒钟*/
    printf("%d Leave SignHandlerNew,signo:%d\n",iSeq,iSignNo);
}
int main(void)
{
    char szBuf[20];/*输入缓冲区,长度为20*/
    int iRet;
    struct sigaction act;/*包含信号处理动作的结构体*/
    act.sa_sigaction=SignHandlerNew;  /*使用sigaction结构体之中的sa_sigaction指定信号处理函数,表示信号附带的参数可以传递到信号处理函数之中,如果不设置信号处理函数sa_siginfo,那么信号处理函数就不能得到信号传递过来的数据,在信号处理函数中对这些信息的访问都将导致段错误*/
    act.sa_flags=SA_SIGINFO;   /*表明信号处理函数由sa_sigaction指定。当信号需要接收附加消息的时候必须给sa_sigaction赋信号处理函数指针,同时还要给sa_flags赋SA_SIGNFO*/
    sigemptyset(&act.sa_mask);
    /*信号集处理函数,将act.sa_mask所指向的信号集清空,即不包含任何信号,sa_mask指定在信号处理程序执行过程中,哪些信号应当被阻塞。默认当前信号本身被阻塞*/
    sigaction(SIGINT,&act,NULL);   /*注册SIGINT信号,按下CTRL+C的时候SIGINT信号被发送*/
    sigaction(SIGQUIT,&act,NULL);  /* 注册SIGQUIT信号,按下CTRL+\的时候信号被发送*/
    do{
	       iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);  /*从标准输入读入数据,其中STDIN_FILENO是指文件描述符,szBuf是读取数据缓存区,sizeof(szBud)-1是数据缓存区的大小,若是成功,则read函数返回读到的字节数目*/
	       if(iRet<0)//如果iRet<0,很明显,发生错误了呗
	       {
	           perror("read fail.");
	           break;   /* read出错退出*/
	       }
	       szBuf[iRet]=0;
	       printf("Get: %s",szBuf);    /*打印终端输入的字符串*/
       }while(strcmp(szBuf,"quit\n")!=0);   /*输入"quit"时退出程序,strcmp是字符串比较函数,返回比较结果,如果不相同则继续执行循环*/
    return 0;
}
/*这个程序在分析的时候我一直搞不懂在干什么,就算是查了每一个函数,每一个符号,还是云里雾里,直到我在Linux上面运行了一次,输入一段数字按回车后输出"Get:数字",按CTRL+\或者CTRL+C之后执行的是SignHandlerNew函数,这时候我才知道,原来read是它的输入语句,然后SignHandlerNew是一个结构体内的函数,当我们发送信号的时候才会执行结构体中的函数,并且执行了read以至于输入缓冲区没有数据而出错*/

运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值