命名管道:(由于匿名管道(没有名字,没有路径)通信只能具有亲缘关系的进程之间能,大大限制了进程间通信的能力)
命名管道的特点:
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;
}