进程通讯(命名管道,信号集)

版权声明:请在征得作者同意的情况下,可以进行非盈利性引用。引用请注明出处:“作者:慕华思弦 转载地址” 字样,以尊重作者的劳动成果,并保持良好的版权意识。 https://blog.csdn.net/Superman___007/article/details/82779669

命名管道:(由于匿名管道(没有名字,没有路径)通信只能具有亲缘关系的进程之间能,大大限制了进程间通信的能力)

命名管道的特点:

       1、可以使用不同进程(无论是否有亲缘关系的进程)通信

       2、是一个特殊文件:文件名与路径(文件系统中),是一个FIFO的文件(没有lssek)

       3、普通在读写方面没有阻塞,而FIFO文件却与普通不同在读写方面:

             进程读:
                                1、若该FIFO管道是阻塞打开,且FIFO文件中没有内容则阻塞等待,直有到信息写入。
                                2、若该FIFO管道是非阻塞打开,无论FIFO中是否有内容,都不会阻塞等待。

             进程写:
                                1、非阻塞打开文件,无论读进程是否读取了,都会立即执行
                                2、阻塞打开文件,如果读进程不读取完成,则写进程一直等待

             注:fifo默认是阻塞文件。

API:创建一个管道文件:    
             int mkfifo(const char *pathname, mode_t mode);
             返回值:0成功  -1失败  错误码在errno中
             pathname:路径
             mode:权限

   阻塞模式创建命名管道文件 ./info  对管道文件进行写入数据 .

#include<iostream>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
//系统错误
#include<errno.h>
using namespace std;
int main()//写进程
{
//1第一步:创建管道named文件
	if(mkfifo("./info",0644)<0)
	{
		if(EEXIST!=errno)
		{
			perror("mkfifo fail");	
			return -1;
		}
	}
//1打开写入:以只读和非阻塞打开
	int fd=open("./info",O_WRONLY);	
//2操作
	char msg[100]="I Love You!#Do you love me?";
	cout<<write(fd,msg,strlen(msg))<<endl;	
//3关闭	
	close(fd);	
}

   新建一个文件 , 用于读取命名管道里面的数据 ./info  .

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
using namespace std;
int main()
{
	//打开
	int fd=open("./info",O_RDONLY);
	if(fd<0)
	{
		perror("open fail\n");
		return -1;
	}
	//读取
	char ch;
	while(read(fd,&ch,1)>0)
	{
		if(ch=='#')
			cout<<endl;
		else
			cout<<ch;
	}
	cout<<endl;
	close(fd);
	return 0;
}

   非阻塞模式打开文件  O_NONBLOCK 方式打开 .

#include<iostream>
#include<sys/stat.h>
#include<sys/types.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
using namespace std;
int main()
{
	//打开
	int fd=open("./info",O_RDONLY|O_NONBLOCK);
	if(fd<0)
	{
		perror("open fail\n");
		return -1;
	}
	//读取
	char ch;
	while(read(fd,&ch,1)>0)
	{
		if(ch=='#')
			cout<<endl;
		else
			cout<<ch;
	}
	cout<<endl;
	close(fd);
	return 0;
}

  信号:(system IPC:UNIX)是比较古老的进程间通信的一种方法。主要是向另外一个进程发出通知。

  1、信号:系统给每一个信号都取了一个编号:
                shell:    Kill -l  
                31号信号之前代表不靠信号
                34信号之后可靠(链式结构)
                shell: man 7 signal (具体的说明)
               1)   SIGHUP   停止进程  终端退出时
               2)   SIGINT  停止进程  Ctrl+C组合键,发出
               9)   SIGKILL 停止进程  用户退出进程
              14)  SIGALRM 时钟闹钟
              10)  SIGUSER1 12)SIGUSER2  用户自定义信号
              17)  SIGCHLD 子进程退出,子进程发送给信息给父进程

    信号的处理方式:
              1、系统默认处理SIG_DFL
              2、用户自处理
              3、忽略;SIG_IGN

    产生一个信号:
              1、硬件产生:  ctrl+c  硬件产生一个信号    结束
                         ctrl+/  硬件产生一个信号    结束(产生一个core文件)
              2、系统产生:
                         子进程退出,给父进程发送信号
              3、用户调用内核API来产生:
                         kill  raise   alarm    pause
                         int kill(pid_t pid, int sig);
                         pid:进程的ID  sig信号标识
                         int raise(int sig);    
                         unsigned int alarm(unsigned int seconds);
                    注:只允许定义一个闹钟,多个会被最新的替换
                         pause()  等待任意一个信号到来就唤醒。
                    注:信号处理是异步方式
        (同步与异步)

              处理信息的步骤:
                   1、注册:信号+处理方式
                   2、信号的产生

         拓展:
                  前端进程:进程在终端上运行
                  后台进程:脱离终端,在后参运行。    可执行文件 &

        信号集 :
                  使用信号集函数处理一组信号,这些信号按照调用的先后次序分为如下几类:
                   1、创建信号集:
                   2、登记信号:决定进程如何处理信号
                   3、信号的处理与检测:

         创建信号集
         int sigemptyset(sigset_t *set);//清空信号集
         int sigfillset(sigset_t *set);    //填满 
         int sigaddset(sigset_t *set, int signum);//增加某个信号
         int sigdelset(sigset_t *set, int signum);//删除某个信号
         int sigismember(const sigset_t *set, int signum);//查询信号是否在该信号集中

   

    创建信号集 , signal(SIGINT,sigfun);             ---->用户自处理

                         signal(SIGINT,SIG_DFL);        ---->系统默认处理

    设置信号集的功能:
                         int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
                         how:指定信号集的的
                         set:信号集
                         olds:把回之前的信号集  

     指定信号集的动作:
                         int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
                         act:将进程的信号集修改
                         old:返回修改前的信号集

#include<iostream>
#include<signal.h>
using namespace std;
//信号用户自处理
void sigfun(int sig)
{
	//用户发送SIGINT(Ctrl+C)
	if(SIGINT==sig)
	{
		cout<<"用户想干掉我"<<endl;
	}
}
int main()
{
//1注册信号: signal  用户输入CTRL+C 时,发出信号
	//signal(SIGINT,sigfun);//用户自处理
	//系统默认处理
	//signal(SIGINT,SIG_DFL);
	//系统收到此信号,但要求忽略处理
	signal(SIGINT,SIG_IGN);
	while(1)
	{
		cout<<"I`m working"<<endl;
		sleep(1);
	}
	return 0;
}

   闹钟的信号 .

#include<iostream>
#include<signal.h>
#include<stdlib.h>
using namespace std;
void sigfun(int sig)
{
	if(sig==SIGALRM)
	{
		cout<<"闹钟响啦,休息一下"<<endl;
	}
}
int main()
{
//1定义信号
	signal(SIGALRM,sigfun);

//定时: 10到了,会给本进程发送一个SIGALRM的信号
	alarm(10);
	alarm(2);

	while(1)
	{
		cout<<"I`m working"<<endl;
		sleep(1);
	}
}

      闹钟信号 .

#include<iostream>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
using namespace std;
void sigfun(int sig)
{
	if(SIGALRM==sig)
	{
		cout<<"闹钟响了"<<endl;
	}
	else if(SIGINT==sig)
	{
		cout<<"ctrl+c被按下"<<endl;
	}
}
int main()
{
	//注册消息
	signal(SIGALRM,sigfun);
	signal(SIGINT,sigfun);//Ctrl+C 
	//定义一个闹钟
	//alarm(5);//定义5秒
	//阻塞等待信号的到来
	//pause();
	sleep(100);
	while(1)
	{
		cout<<"哈哈,我在玩..."<<endl;
		sleep(1);
	}
	return 0;
}

   信号集的实现 .

#include<iostream>
#include<stdio.h>
#include<signal.h>
using namespace std;
void sigfun(int sig)
{
	if(SIGINT==sig)
	{
		cout<<"如果你想退出进程,请按Ctrl+\\"<<endl;
	}
}
//SIGQUIT SIGINT SIGALARM加入信号集,然后设置为阻塞状态,当该等待5秒之后再恢复
int main()
{
	signal(SIGINT,sigfun);
	//1创建一个信号集(替换进程的集号)
	sigset_t set;
	if(-1==sigemptyset(&set))//1先清空(set是随机值,可能包含其他信号)
	{
		perror("clear fail");
		return -1;
	}
	//1.1添加上述两个信号到信号集中
	if(sigaddset(&set,SIGQUIT)<0)
	{
		perror("add fail");
		return -1;
	}
	if(sigaddset(&set,SIGINT)<0)
	{
		perror("add fail");
		return -1;
	}
	sigset_t oldset;
	//2.决定信号集的处理---阻塞模式
	if(sigprocmask(SIG_BLOCK,&set,&oldset)<0)
	{
		perror("procmask fail");
		return -1;
	}
	//睡眠10s
	sleep(10);
	cout<<"10休息完成"<<endl;
	//恢复之前的状态
	if(sigismember(&oldset,SIGINT)==1)
	{
		cout<<"SIGINT在该信号集中"<<endl;
	}
	else
		cout<<"不在"<<endl;
	sigprocmask(SIG_UNBLOCK,&set,NULL);
	sleep(20);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Superman___007/article/details/82779669