Linux软件编程(八)进程间通信(信号、共享内存、信号量、消息队列)

发布于:2025-08-20 ⋅ 阅读:(17) ⋅ 点赞:(0)

1. 信号(Signal)

1.1 基本概念

  • 信号:实现进程间的通知机制,本质是一种 软中断,用于进程间的 异步通信

  • 异步通信:接收方不知道什么时候发送方会发来数据。

1.2 系统支持的信号

         1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX    

  • 查看命令:kill -l

常见信号:

  2) SIGINT:ctrl + c 
       让一个进程被打断
    3) SIGQUIT:ctrl + \
        让一个进程结束
    9) SIGKILL:
        强制让一个进程结束
    11)SIGSEGV:
        让一个进程结束(段错误)
    13)SIGPIPE:
        让一个进程结束(管道破裂)
    14)SIGALRM:
        让一个进程结束(定时时间到达)
    17)SIGCHLD:
        子进程结束时发送给父进程
    18)SIGCONT:
        让停止态的进程继续执行
    19)SIGSTOP:
        让运行态的进程进入停止态(暂停)强制停止
    20)SIGTSTP:
        ctrl + z   让进程进入暂停态,后台进程
        来自终端的停止信号


      10) SIGUSR1
      12) SIGUSR2
      用户可自定义的信号

      9) SIGKILL
      19)    SIGSTOP
      管理员信号:只能按照默认方式处理,不能够被忽略和捕获。

注意:

  • 管理员信号(如 SIGKILLSIGSTOP)只能默认处理,不能捕获或忽略。

1.3 信号处理流程

  1. 进程收到信号后,打断当前执行,去处理该信号。

  2. 信号处理完成后,进程继续原来的执行。

  3. 信号处理方式:

    • 缺省:系统默认处理

    • 忽略:不处理

    • 捕获:调用用户自定义的信号处理函数

1.4 注册信号

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

功能:设置信号的处理方式(注册一个信号)

参数:

signum:此处填要处理的信号的编号或名字(eg: 10 或者 SIGUSR1 代表用户自定义的信号 )

handler:处理方式

   (1)SIG_IGN: 以忽略方式处理该信号(不处理)
   (2)SIG_DFL:以缺省方式处理(系统默认方式)
   (3)函数的地址:以捕获方式处理(自定义)(传入自定义的函数名即可即为函数的首元素地址)

            函数类型应为  sighandler_t handler 型,即typedef void (*sighandler_t)(int);  类型的函数,                 此函数返回值类型为void型,形参类型为int型,eg: void handler(int signum);                     

 返回值:
               失败:NULL
               自定义方式:返回自定义的函数入口。

     void (*sighandler_t)(int signum);
     sighandler_t:执行信号任务处理函数的入口
     参数:
            signum:触发该任务函数的信号

  • 注意:1. 若信号不被注册,则按照默认方式处理
               2. 信号只需注册一次即可;
               3. 每次信号的到来都会触发一次信号任务处理函数;
               4. 信号尽可能早注册。

1.5 发送信号

  • 命令方式kill -信号 PID

  •     1)kill 命令
         2)  kill();
               int kill(pid_t pid, int sig);
               功能:给指定的进程发送一个信号
               参数:
                     pid:接收信号的进程PID
                     sig:信号的编号
               返回值:
                    成功:0;
                    失败:-1;
           3)子进程结束时,会发送SIGCHLD信号给父进程
               子进程空间异步回收:通过子进程发送的SIGCHLD信号实现。

           4)int raise(int sig);
               给自己所在的进程发送信号
             
           5)unsigned int alarm(unsigned int seconds);
                 功能:设置一个闹钟,当闹钟时间到达时,
                             向自己所在的进程发送一个SIGALRM的信号
                 参数:
                         seconds:设置的闹钟的定时时间
                 返回值:  
                   成功返回上次设定剩余的时间
                  上次未设定则返回0

             6)pause();
                功能:让一个进程挂起(进入到睡眠状态)
                注意:
                      1. pause可以被一个信号唤醒
                      2. 这个信号必须要被捕获

  1. eg: 检测用户输入:如果 3 秒内没有输入,算一次超时,累计 3 次超时自动退出。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <pthread.h>

int cnt = 1;

void handler(int sighum)
{    
    printf("超时%d\n", cnt);
    if(cnt == 3)
    {
        exit(0);
    }
    alarm(3);
    cnt++;
}

int main(int argc, char const *argv[])
{
    char buff[1024] = {0};
    
    signal(SIGALRM, handler);
    alarm(3);
    
    while(1)
    {
        fgets(buff, sizeof(buff), stdin);
        cnt = 1;
        alarm(3);       
    }

    return 0;
}

2. 共享内存(Shared Memory)

2.1 概念

  • 共享内存是 进程间通信效率最高 的方式。

  • 使用内核空间中的内存区域共享数据。

  • 使用内存映射技术,减少的数据的反复拷贝,提高了通信效率。

2.2 操作流程

 IPC对象

       1)创建一个IPC key:
             key_t ftok(const char *pathname, int proj_id);
       2)  创建共享内存:
             int shmget(key_t key, size_t size, int shmflg);
       3)  建立共享内存段和用户空间的内存映射:
             void *shmat(int shmid, const void *shmaddr, int shmflg);
       4)  向共享内存写入数据--》通过用户空间的首地址
       5)解除映射关系
             int shmdt(const void *shmaddr);
       6)删除共享内存
             int shmctl(int shmid, int cmd, struct shmid_ds *buf);


       #include <sys/types.h>
       #include <sys/ipc.h>

       key_t ftok(const char *pathname, int proj_id);
       功能:创建一个IPC key
       参数:
               pathname:路径
               proj_id: 工程ID
               注意:两个进程在创建KEY时必须使用相同的参数
      返回值:
               成功:IPC key
               失败:-1
       int shmget(key_t key, size_t size, int shmflg);
       功能:创建一个共享内存
       参数:
               key:IPC key
               size:共享内存的大小
                          会被扩展成PAGE_SIZE(4096bytes)的整数倍
              shmflg:
                            IPC_CREAT | 0664
       返回值:
                成功:共享内存的ID
                失败:-1

     void *shmat(int shmid, const void *shmaddr, int shmflg);
     功能:建立共享内存内存映射
     参数:
          shmid :共享内存id
          shmaddr:映射的用户空间首地址
                           NULL:让操作系统分配
         shmflg:
                       SHM_RDONLY:只读
                       !SHM_RDONLY:可读可写
     返回值:
          成功:映射的用户空间首地址
          失败:(void *) -1

     int shmdt(const void *shmaddr);
     功能:解除内存映射关系
     参数:
              shmaddr:要解除的用户空间首地址
     返回值:
        成功:0
        失败:-1
 
      int shmctl(int shmid, int cmd, struct shmid_ds *buf);
      功能:操作共享内存
      参数:
              shmid:要操作的共享内存id
              cmd:要执行的操作指令
                          IPC_RMID:删除操作
              buf:设置的参数
      返回值:
              成功:0
               失败:-1

2.3 常用命令

  • ipcs -a:查看所有 IPC 对象

  • ipcrm -s:删除信号量集

  • ipcrm -m 删除共享内存

  • ipcrm -m shmid:按 ID 删除共享内存

  • ipcrm -M shmkey:按 key 删除共享内存


3. 信号量集(Semaphore Set)

  • 作用:实现进程间同步。

  • 原理:通过对资源的加锁/解锁,保证一次只有一个进程访问共享资源。

  • 常用于:配合共享内存,避免多个进程同时修改导致数据混乱。


4. 消息队列(Message Queue)

  • 概念:类似管道的通信机制,但支持消息分等级。

  • 特点

    • 进程间通信,带同步效果

    • 每条消息有优先级(数值越小优先级越高)

    • 增加数据的等级(优先级:优先级数据越小,优先级越高)


网站公告

今日签到

点亮在社区的每一天
去签到