Ubuntu下UnixC的第十天

本文深入探讨了进程间通信的有名管道和信号处理机制,包括信号的基础、产生、阻塞及处理,信号集操作,以及如何使用systemvipc进行进程间通信。详细介绍了信号的阻塞与忽略、未决信号集的获取、信号从产生到处理的过程,以及使用ftok、msgget等函数进行消息队列的创建和消息的发送与接收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回忆昨天内容
一、有名管道
    管道类型的文件  大小始终为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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值