回忆昨天内容
一、有名管道
管道类型的文件 大小始终为0
用于进程间的通信 任意进程
mkfifo(3)
二、信号的基础
软件实现的中断机制
64个信号 使用 kill -l命令查看
信号编号 信号名
信号的产生、 信号的递达给进程(或在此前被阻塞) 进程对信号的处理
信号处于未决状态 未决信号
三、改变进程对信号的处理
signal(2)
向进程注册信号处理函数
处理函数的类型
三种方法:SIG_DFL默认 SIG_IGN忽略 user_define用户自定义
进程默认的继承信号处理函数
四、信号的产生
三种
1硬件产生 ctrl+
2linux命令给进程发送信号 kill
3使用库函数或者系统调用给进程发送信号
kill(2) raise(3) alarm(2)
pending clock
pause(2)
暂停 等待信号打断
只在错误时返回-1 errno被设置
read从管道读取数据时,如果管道里为空,阻塞,返回-1
五、信号的阻塞
sigset_t 信号集类型
这种类型相关的操作
#include <signal.h>
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);
今天的内容
一、信号的阻塞
sigprocmask(2)
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:检查或者改变阻塞信号集
参数:
how
SIG_BLOCK 当前信号掩码集和set的并集设置为进程的信号掩码集
SIG_UNBLOCK 将set集合中的信号从当前信号掩码集中移除
SIG_SETMASK 将参数set设置为当前进程的信号掩码集
set 指定要拿来操作旧信号集的新信号集
oldset 如果不空,将旧的信号掩码集存储到这里
返回值:
成功 0
错误-1 errno被设置
让当前进程阻塞2 3 信号 编写程序实现 代码参见blocked.c
信号阻塞 忽略信号
信号的忽略是信号到达了,进程对信号的处理动作
信号阻塞,是信号还没有抵达进程
在进程阻塞信号期间,给信号多次发送信号,在进程解除对信号的处理的时候,只对信号处理一次,造成了信号的丢失。
这种信号称为不可靠信号。1-31 为不可靠信号
可靠信号在上边那种情况下,不会造成信号的丢失。
34-64 实时信号(可靠)
二、获取进程的未决信号集
发送给进程的信号,还没有处理的信号,会记录到一个集合中。这个集合就是进程的未决信号集。
获取进程的未决信号集,检测信号是不是未决信号集中的一员?
如何获取未决信号集?
sigpending(2)
#include <signal.h>
int sigpending(sigset_t *set);
功能:获取进程的未决信号集
参数:
set 将进程的未决信号集存储在set指定的地址空间里
返回值:成功 0 错误-1 errno被设置
编写代码 获取进程的未决信号集 检测2号信号是不是未决状态
代码参见 pending.c
三、信号从产生到处理的整个过程
1 在bash上启动一个进程
2 按下Ctrl+c键,产生硬件中断 cpu切换到内核态执行按键的驱动程序
驱动程序将该按键解释为2号信号,记录到进程PCB中
3 当进程从内核态切换到用户态的时候,检查进程的PCB中是否有信号的记录
有,代表信号到达进程 没有,就说明没有信号到达
4 如果有信号到达,调用信号的处理程序 处理程序执行完毕 调用sigreturn(2)
返回到进程的内核态 回到第三步继续
5 没有信号到达 进程直接返回用户态 继续后面的工作
四、system v ipc
看看这些对象 ipcs
system v ipc 对象
每个对象都有自己的唯一id。内核通过对象的id来管理这些对象。
用户态使用怎么办?
进程要想获取一个ipc的对象,必须要有一个ipc的key值(键值)
用户如何去获取一个key值
ftok(3)
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:获取一个system v ipc的键值
参数: pathname 指定一个有效的文件名(存在 可访问的)
proj_id 使用这个整数的低有效八位
返回值: 成功返回system v ipc 的键值
失败 -1 errno被设置
举例说明:使用ftok(3)获取一个system v ipc的键值
代码参见 ftok.c
msgget shmget semget
消息队列
使用键值获取一个消息队列的id
msgget(2)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:获取一个system v ipc的消息队列id
如果没有跟key绑定的id,在msgflg指定了IPC_CREAT,创建一个新的消息队列
并返回该消息队列的id,如果有,不创建
参数:
key 是ftok(3)的返回值
msgflg
IPC_CREAT 如果没有消息队列则创建
IPC_EXCL 如果存在消息队列,则报错
mode 指定消息队列的权限
返回值:成功 返回消息队列的id(非负整数)
失败 -1 errno被设置
获取一个消息队列的id ,如果消息队列不存在,创建这个消息队列,并返回该消息队列的id,
如果存在,直接返回该消息队列的id
代码参见 msgget.c
向消息队列发送消息
msgsnd(2)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能: 发送消息给消息队列
参数: msqid 目的消息队列的id
msgp 消息 指针类型的变量 指向了消息的地址
msgsz 指定了mtext的有效空间大小
msgflg : a bit mask
IPC_NOWAIT: 如果消息队列没有充足的空间,立即返回,报错
0 : 如果消息队列没有充足的空间,等待空间充足
返回值: 成功0 错误 -1 errno被设置
举例:向消息队列发送一条消息 代码参见 psnd.c
caller define
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
char mtext[1]; metext是常量,是数组首地址
char mtext; 是变量
从消息队列获取消息
msgrcv(2)
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
功能:从消息队列接收一条消息
参数:
msqid 指定消息队列 从这个消息队列中取出一条消息
msgp 将取出的消息放到该地址处
msgsz 指定mtext成员最大字节数
msgtyp 指定请求接收的消息的类型 >0时接收消息队列的第一个
msgflg
IPC_NOWAIT 如果没有消息,立即返回错误,errno被设置
0:如果消息队列中没有消息 ,等待消息的到来
返回值:失败 -1 errno被设置
成功返回实际接收到的消息的字节数
共享内存
信号量集
blocked.c
#include<t_stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
sigset_t set,oset;
void handle(int n){
printf("n=%d\n",n);
return;
}
void handle2(int n){
printf("n=%d\n",n);
exit(0);
}
//对2 3 信号进行阻塞
int main(){
signal(2,handle);
signal(3,handle2);
sigemptyset(&set);
sigaddset(&set,2);
sigaddset(&set,3);
//将信号集SET设置为进程的信号掩码集
int spm=sigprocmask(SIG_SETMASK,&set,&oset);
if(spm==-1) E_MSG("sigprocmask",-1);
int j=200000;
sleep(2);
for(int i=0;i<500000;i++)
printf("i=%d\n",i);
//恢复 2 3
printf("恢复\n");
sigprocmask(SIG_SETMASK,&oset,NULL);
while(1);
return 0;
}
ftok.c
#include <sys/types.h>
#include <sys/ipc.h>
#include<t_stdio.h>
int main(int argc,char* argv[])
{
//获取一个system v ipc 的键值
key_t key;
key=ftok(argv[1],77);
if(key==-1) E_MSG("ftok",-1);
printf("key=0x%x\n",key);
return 0;
}
msgget.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<t_stdio.h>
int main(int argc,char* argv[]){
//获取一个system v ipc 的键值
key_t key;
key=ftok(argv[1],77);
if(key==-1) E_MSG("ftok",-1);
printf("key=0x%x\n",key);
//使用key值获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0644);
if(msqid==-1) E_MSG("msgget",-1);
printf("msqid=%d\n",msqid);
return 0;
}
pending.c
#include<t_stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
sigset_t set,oset,pset;
void handle(int n){
printf("n=%d\n",n);
return;
}
#if 0
void handle2(int n){
printf("n=%d\n",n);
exit(0);
}
#endif
//对2 信号进行阻塞
int main(){
signal(3,handle);
signal(2,handle);
sigfillset(&set);//2在信号集中,2被阻塞
sigemptyset(&oset);
sigaddset(&oset,2);//oset信号集中只有2
sigdelset(&set,3);//3没有被阻塞
int spm=sigprocmask(SIG_SETMASK,&set,NULL);
if(spm==-1) E_MSG("sigprocmask",-1);
while(1){
sleep(2);
sigpending(&pset);
int b=sigismember(&pset,2);
//检测是否是未决信号
if(getchar()){
if(b==1)
{
printf("2 pending signal\n");
// sigdelset(&pset,2);
sigprocmask(SIG_UNBLOCK,&oset,NULL);//放开阻塞2
}
else
printf("2 not pending signal\n");
sigprocmask(SIG_BLOCK,&oset,NULL);//阻塞2
}
if(getchar()==0)
break;
}
// 设置信号,阻塞,发送,获取未决信号集,判断,恢复阻塞
// printf("恢复\n");
// while(1);
return 0;
}
prcv.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<t_stdio.h>
#include<string.h>
#include<unistd.h>
//用户自定义的结构体类型
typedef struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
}msg_t;
int main(int argc,char* argv[]){
msg_t msg;
//获取一个system v ipc 的键值
key_t key;
key=ftok(argv[1],77);
if(key==-1)
E_MSG("ftok",-1);
printf("key=0x%x\n",key);
//使用key值获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0644);
if(msqid==-1)
E_MSG("msgget",-1);
printf("msqid=%d\n",msqid);
//初始化消息的结构体内容
// msg.mtype=3;
// strcpy(msg.mtext,"this is a test...\n");
//向消息队列发送消息
int rcv=msgrcv(msqid,&msg,256,3,IPC_NOWAIT);
if(rcv==-1)
E_MSG("msgsnd",-1);
// msg.mtext[rcv]='\n';
write(1,msg.mtext,rcv);
return 0;
}
psnd.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<t_stdio.h>
#include<string.h>
//用户自定义的结构体类型
typedef struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[256]; /* message data */
}msg_t;
int main(int argc,char* argv[]){
msg_t msg;
//获取一个system v ipc 的键值
key_t key;
key=ftok(argv[1],77);
if(key==-1)
E_MSG("ftok",-1);
printf("key=0x%x\n",key);
//使用key值获取消息队列的id
int msqid=msgget(key,IPC_CREAT|0644);
if(msqid==-1)
E_MSG("msgget",-1);
printf("msqid=%d\n",msqid);
//初始化消息的结构体内容
msg.mtype=3;
strcpy(msg.mtext,"this is a test...\n");
//向消息队列发送消息
int snd=msgsnd(msqid,&msg,strlen(msg.mtext),0);
if(snd==-1)
E_MSG("msgsnd",-1);
return 0;
}