linux 信号

简介: linux 信号

信号:消息,通知进程系统中发生了某种类型的事件,每种类型的信号对应某种系统事件。

信号是进程间通信的一种异步通信机制。在进程运行过程中,经常会产生一些事件,这些事件的产生和进程的执行往往是异步的,信号提供了一种在软件层面上的异步处理事件的机制。在硬件层面上的异步处理机制是中断,信号是中断的软件模拟。

每个信号用一个整型常量宏表示,以 SIG开头,在头文件<signal.h>中定义

# 查看信号列表
 kill -l 
 man 7 signal

1、信号的实现机制

发送信号到目的进程是由发送信号和接收信号两个步骤组成。

  • 发送信号:内核通过更新目的进程上下文中的某个状态,发送一个信号给目的进程。
  • 接收信号:目的进程被内核强迫以某种方式对信号的发送做出反应。


待处理信号(pending signal):一个发出而没有接收的信号,又称为挂起信号或未决信号。

在任何时候,一种类型的信号至多只会有一个待处理信号。也就是说,如果一个进程有一个类型为 k 的待处理信号,那么任何接下来发送到这个进程的类型为 k 的信号都不会排队等待,它们只是被简单丢弃。一个进程可以选择性地阻塞接收某种信号,当一种信号被阻塞,它仍可以被发送,但是产生的待处理信号不会被接收,直到进程取消对这种信号的阻塞。

一个待处理信号最多只能被接收一次。内核为每个进程,在位图 pending 中维护着待处理信号的结合,在位图 blocked 集合(信号屏蔽字)中维护着被阻塞的信号集合。只要发送了一个类型为 k 的信号,内核就会设置 pending中的第 k 位,只要接收了一个类型为 k 的信号,内核就会清楚 pending中的第 k 位。

2、发送信号

2.1、发送信号的原因

  • 内核检测到系统事件,例除零错误等
  • 进程调用 kill 函数

2.2、发送信号的机制

unix 系统提供了大量向进程发送信号的机制,这些机制都是基于进程组的。每个进程拥有自己的 pid,每个进程属于一个进程组 pgid

硬件来源:键盘。硬件触发中断,操作系统切换到内核态执行中断处理程序,中断处理程序发送信号,进程接收信号并处理。

ctrl + c: SIGINT,表示终止该进程
 ctrl + z: SIGTSTP,表示挂起该进程

软件来源:/bin/kill 程序,kill 函数,定时器函数。

kill 函数

进程通过 kill 函数发送信号给其他进程(包括自己)。

/*
 返回值:成功返回 0,失败返回 -1
 参数
 - pid: pid > 0,发送 sig 信号给进程 pid
        pid = 0, 发送 sig 信号给调用进程所在进程组中的每个进程(包括调用进程自己)
        pid < 0,发送 sig 信号给进程组 |pid| 中的每个进程
 - sig: 信号类型
 */
 int kill(pid_t pid, int sig);

3、接收信号

进程接收到信号,有三种处理方法:

  • 默认处理:signal(SIGINT,SIG_DFL)
    - Term:终止当前进程
    - Ign:忽略该信号
    - Core:终止当前进程,并且产生core dump
    - Stop:停止(挂起)一个进程
    - Cont:使当前停止的进程,继续运行
  • 忽略信号:signal(SIGSEGV,SIG_IGN)
  • 捕捉信号:自定义信号处理函数。用户自定义信号处理函数的目的就是实现进程的有序退出。

自定义信号处理函数设置原则

  • 程序尽可能简单。例:处理程序简单设置全局标志并返回,所有与接收信号相关的处理由主程序执行。
  • 函数内部只调用信号异步安全函数

安全函数:可重入的(例只访问局部变量),不能被信号处理程序中断。

3.1、处理信号

signal 函数

进程可以通过signal函数修改和信号相关联的默认行为。注意:SIGKILLSIGSTOP这两个信号既不能被忽略也不能被捕捉,即进程接收到这两个信号后,只能接受系统的默认处理,即终止进程。

# include <signal.h> 
 // 信号回调函数,信号处理
 typedef void (*sighandler_t)(int);
 /*
 功能:捕获信号
 返回值:成功返回前次处理程序的指针,失败返回 SIG_ERR
 参数:
 - signum:要捕捉的信号值,
 - handler:函数处理函数。SIG_DFL 默认处理; SIG_IGN,忽略信号; 其他,执行信号回调函数
 */ 
 sighandler_t signal(int signum, sighandler_t handler);

sigaction 函数

signal函数处理机制在多信号处理的场景下

  • 收到不同类型的信号:中断当前信号处理,优先处理新的信号,处理完后返回继续处理当前信号。
  • 收到相同类型的信号:执行完当前信号处理,然后只执行新的相同信号一次,重复的信号被忽略。
  • 当前进程阻塞在系统调用上,收到一个信号后,中断系统调用,执行信号处理函数。

不同的系统有不同的信号处理语义,但 signal函数的处理过程是固定的,无法调整。因此,Posix 标准定义了sigaction函数,允许用户自定义这些场景下进程的行为。

/*
 返回值:成功返回0,失败返回-1。
 参数:
 - signum:要捕捉的信号值 
 - act:自定义行为
 - oldact:保存原来信号的回调函数,通常传入空指针
 */
 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)

其中 sigaction 结构体

struct sigaction {    
     // 联合体,新旧处理函数只有一个可以生效  
     union { 
         // 旧类型的信号处理函数 
         __sighandler_t _sa_handler; 
         // 新类型的信号处理函数,siginfo_t 保存信号的相关信息
         void (*_sa_sigaction)(int, struct siginfo *, void *);
     } _u;
     // 阻塞信号的结合 
     sigset_t sa_mask; 
     // 信号处理的方式,旧类型填 0。其他例如:
     // SA_SIGINFO,选择回调函数 sa_sigaction; 
     unsigned long sa_flags; 
     // 保留不用
     void (*sa_restorer)(void);
 };

3.2、信号阻塞 | 解除

Linux 提供阻塞信号的机制

  • 隐式阻塞机制:内核默认阻塞任何当前处理程序正在处理信号类型的待处理信号。
  • 显式阻塞机制: sigprocmask 函数

sigset_t 信号集合

#include <signal.h> 
 typedef struct { 
     unsigned long int __val[(1024/(8*sizeof(unsigned long int)))]; 
 } __sigset_t; 
 // sigset_t的本质就是一个位图,共有1024位
 typedef __sigset_t sigset_t; 
 // 初始化信号集,清除所有信号 
 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);

sigpending 函数

获取当前待处理信号的集合。通常在回调函数当中使用的,用于检查当前是否阻塞了某个信号

/*
 返回值:成功返回0,失败返回-1
 参数 set: 要检测的信号
 */
 int sigpending(sigset_t *set);

sigprocmask 函数

改变当前阻塞的信号集合(位图 blocked

/*
 返回值:成功返回0, 失败返回-1
 参数
 - how:
     SIG_BLOCK: 把集合 set 中的信号加入到阻塞集合 blocked 当中 (blocked |= set)
     SIG_UNBLOCK: 把集合 set 从阻塞集合 blocked 中删除 (blocked = blocked & ~set)
     SIG_SETMASK: 把集合 set 替换阻塞集合 blocked (blocked = set)
 - set:阻塞集合
 - 参数3:原有的集合
 */
 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

sigsuspend 函数

使用 sigprocmask 函数可以实现信号保护临界区。在临界区执行代码的时候,此时产生的信号将会被阻塞,临界区结束的位置只需要再使用 sigprocmask 即可。pause 系统调用可以唤醒一个阻塞进程,直到被一个信号唤醒。若采用 pause 函数捕捉临界区的信号,信号解除阻塞后,立即执行信号处理函数,无法捕捉信号。

为了捕捉临界区的信号,将解除阻塞和等待信号合并成一个原子操作,就是sigsuspend函数

int sigsuspend(const sigset_t *mask);

4、定时器

4.1、睡眠函数

sleep 函数

#include <unistd.h>
 // 休眠 sec 秒
 unsigned int sleep(unsigned int seconds);
 // 休眠 usec 秒
 int usleep(useconds_t usec);

pause 函数

阻塞一个进程,直到某个信号被递送时,进程会解除阻塞,然后终止进程或者执行信号处理函数

int pause(void);

alarm 函数

进程调用 alarm 函数向它自己发送 SIGALRM信号。

/*
 返回值:前一次闹钟剩余的秒数,若以前没有设定闹钟,则为 0
 参数:seconds: 闹钟的时间间隔
 */
 unsigned int alarm(unsigned int seconds);

alarm 函数安排内核在 secs 秒后发送一个 SIGALRM 信号给调用进程。在任何情况下,对 alarm 的调用都将取消任何待处理的闹钟,并且返回待处理的闹钟在被发送前还剩下的秒数,若没有代理处理的闹钟,返回 0。

4.2、定时器

setitimer 函数

setitimer 系统调用负责调整间隔定时器。间隔定时器在创建的时候,就会设置一个时间间隔,定时器到达时间间隔时,调用进程会产生一个信号,随后定时器被重置。

定时器的分类

  • 真实计时器:程序实际运行的时间(时钟时间),时间到发送 SIGALARM信号
  • 虚拟计时器:程序在用户态模式下的 CPU 时间,时间到发送SIGVTALARM信号,
  • 实用计时器:程序在用户态和内核态所占用的 CPU 时间,时间到发送 SIGPROF信号

使用 fork 的时候子进程不会继承父进程的定时器,使用 exec 时候,定时器不会销毁。

/*
 返回值:成功返回0,失败返回-1.
 参数:
 - which:设置定时器的种类:真实计时器 SIGALARM、虚拟计时器 SIGVTALARM、实用计时器 SIGPROF
 - new_value:定时器的初始时间  
 - old_value: 定时器的间隔时间    
 */
 int getitimer(int which, struct itimerval *curr_value)
 int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value) 
 struct itimerval { 
     struct timeval it_interval; // 时间间隔 
     struct timeval it_value;    // 初始时间
 }; 
 struct timeval {
     time_t tv_sec;       // 秒 
     suseconds_t tv_usec; // 微秒
 };

例:使用真实计时器,实用计时器,统计程序执行时间,在实用计时器及虚拟计时器设定计时后,先睡眠,再让程序处于while(1)

#include <func.h>
 void sigFunc(int sigNum) {
     time_t now;
     time(&now);
     printf("now time = %s\n", ctime(&now));
 }
 int main(int argc,char*argv[]) {
     //真实计时器,信号SIGALRM
     signal(SIGALRM, sigFunc);
     struct itimerval  Time;
     memset(&Time, 0, sizeof(Time));
     Time.it_value.tv_sec = 1;    // 1s后启动
     Time.it_interval.tv_sec = 2; // 间隔2s
     time_t now;
     time(&now);
     printf("now time = %s", ctime(&now));
     // ITIMER_REAL
     setitimer(ITIMER_REAL, &Time, NULL);
     // ITIMER_PROF
     // setitimer(ITIMER_PROF, &Time, NULL);
     printf("before sleep\n");
     sleep(3);
     printf("after sleep\n");
     while(1);
     return 0;
 }

5、例:四窗口聊天

在四个终端上分别启动A、A1、B、B1四个进程。

  • A 和 B 负责通信,A1和B1负责显示信息。
  • A 和 B 使用有名管道进行通信
  • A 和 A1 进程通信采用共享内存(信号量同步),B 和 B1 进程通信采用消息队列
  • 退出方式:ctrl + ckill 命令,任意进程收到信号后,给所有进程发送 10 号信号,有序退出。有序退出要做的主要有:关闭管道,解除对共享内存的映射,删除共享内存,删除信号量,删除消息队列。

showA

#include <head.h>
 // 保存各个进程的pid
 typedef struct pidnums{
     int pidWriteA;
     int pidWriteB;
     int pidShowA;
     int pidShowB;
 } pidNums_t, *pPidNums_t;
 typedef struct package{
     int flag;
     char buf[64];
 }Package_t, *pPackage_t;
 pPidNums_t pidsets; 
 pPackage_t p;
 // 2 信号处理函数
 void sigFunc2(int signum,siginfo_t *p,void *p1){
     printf("%d is coming\n",signum);
     kill(pidsets->pidWriteA, 10);
     kill(pidsets->pidWriteB, 10);
     kill(pidsets->pidShowB, 10);
     kill(pidsets->pidShowA, 10);
 }
 // 10 信号处理函数:
 void sigFunc10(int signum, siginfo_t *p, void *p1){
     printf("%d is coming\n", signum);
     shmdt(pidsets);
     shmdt(p);
     exit(0);
 }
 int main(int argc, char *argv[]) {
     // 2 号信号
     struct sigaction act2;
     bzero(&act2, sizeof(act2));
     act2.sa_flags = SA_SIGINFO;
     act2.sa_sigaction = sigFunc2;
     int ret = sigaction(SIGINT, &act2, NULL);
     ERROR_CHECK(ret, -1, "sigaction 2");
     // 10 号信号
     struct sigaction act10;
     bzero(&act10, sizeof(act10));
     act10.sa_flags = SA_SIGINFO;
     act10.sa_sigaction = sigFunc10;
     ret = sigaction(10, &act10, NULL);
     ERROR_CHECK(ret, -1, "sigaction 10");
     // 创建共享内存
     int shmid = shmget(1000, 1024, IPC_CREAT|0600);
     ERROR_CHECK(shmid,-1,"shmget");
     // 映射地址空间
     p = (pPackage_t)shmat(shmid,NULL,0);
     ERROR_CHECK(p, (pPackage_t)-1, "shmat");
     int semArrId = semget(1000, 1, IPC_CREAT|0600);
     ERROR_CHECK(semArrId, -1, "semget");
     ret = semctl(semArrId, 0, SETVAL, 1);
     ERROR_CHECK(ret, -1, "semctl");
     struct sembuf sopp, sopv;
     sopp.sem_num = 0;
     sopp.sem_op = -1;
     sopp.sem_flg = SEM_UNDO;
     sopv.sem_num = 0;
     sopv.sem_op = 1;
     sopv.sem_flg = SEM_UNDO;
     int pid = getpid();
     int shmidPid = shmget(2000, 4096, IPC_CREAT|0600);
     ERROR_CHECK(shmidPid,- 1, "pid shmget");
     pidsets = (pPidNums_t)shmat(shmidPid, NULL, 0);
     ERROR_CHECK(pidsets, (pPidNums_t) - 1, "pid shmat");
     pidsets->pidShowA = pid;
     while(1){
         semop(semArrId, &sopp, 1);
         if(p->flag == 1){
             puts(p->buf);
             printf("\n");
             memset(p->buf, 0, sizeof(p->buf));
             p->flag = 0;
         }
         if(p->flag == 2){
             printf("%*s%s\n", 10, "", p->buf);
             memset(p->buf, 0, sizeof(p->buf));
             p->flag = 0;
         }
         semop(semArrId, &sopv, 1);
     }
     return 0;
 }

write A

#include <head.h>
 typedef struct package{
     int flag;
     char buf[64];
 }Package_t, *pPackage_t;
 typedef struct pidnums{
     int pidWriteA;
     int pidWriteB;
     int pidShowA;
     int pidShowB;
 } pidNums_t, *pPidNums_t;
 pPidNums_t pidsets; 
 int fdr = 0,fdw = 0;
 int shmid = 0;
 int semArrId = 0;
 int shmidPid = 0;
 pPackage_t p;
 void sigFunc2(int signum,siginfo_t *p,void *p1){
     printf("%d is coming\n",signum);
     kill(pidsets->pidWriteB, 10);
     kill(pidsets->pidShowA, 10);
     kill(pidsets->pidShowB, 10);
     kill(pidsets->pidWriteA, 10);
 }
 void sigFunc10(int signum,siginfo_t *p,void *p1){
     printf("%d is coming\n", signum);
     semctl(semArrId, 0, IPC_RMID);
     shmdt(p);
     shmdt(pidsets);
     shmctl(shmid, IPC_RMID, NULL);
     shmctl(shmidPid, IPC_RMID, NULL);
     close(fdr);
     close(fdw);
     exit(0);
 }
 int main(int argc,char *argv[]) {
     ARGS_CHECK(argc, 3);
     struct sigaction act2;
     bzero(&act2, sizeof(act2));
     act2.sa_flags = SA_SIGINFO;
     act2.sa_sigaction = sigFunc2;
     int ret = sigaction(SIGINT, &act2, NULL);
     ERROR_CHECK(ret, -1, "sigaction 2");
     struct sigaction act10;
     bzero(&act10, sizeof(act10));
     act10.sa_flags = SA_SIGINFO;
     act10.sa_sigaction = sigFunc10;
     ret=sigaction(10, &act10, NULL);
     ERROR_CHECK(ret, -1, "sigaction 10");
     //A和B的读写管道
     fdr=open(argv[1], O_RDONLY);
     ERROR_CHECK(fdr, -1, "open1");
     fdw=open(argv[2], O_WRONLY);
     ERROR_CHECK(fdw, -1, "open2");
     printf("i am chat1, fdr=%d fdw=%d\n",fdr,fdw);
     char buf[128] = {0};
     fd_set rdset;
     // A和showA之间的共享内存
     shmid=shmget(1000, 1024, IPC_CREAT|0600);
     ERROR_CHECK(shmid, -1, "shmget");
     p=(pPackage_t)shmat(shmid, NULL, 0);
     ERROR_CHECK(p, (pPackage_t) - 1, "shmat");
     p->flag = 0;
     // A和showA之间的互斥锁
     semArrId = semget(1000, 1, IPC_CREAT|0600);
     ERROR_CHECK(semArrId, -1, "semget");
     ret=semctl(semArrId, 0, SETVAL, 1);
     ERROR_CHECK(ret, -1, "semctl");
     struct sembuf sopp, sopv;
     sopp.sem_num = 0;
     sopp.sem_op = -1;
     sopp.sem_flg = SEM_UNDO;
     sopv.sem_num = 0;
     sopv.sem_op = 1;
     sopv.sem_flg = SEM_UNDO;
     // pid存储的共享内存
     int pid = getpid();
     shmidPid = shmget(2000, 4096, IPC_CREAT|0600);
     ERROR_CHECK(shmidPid, -1, "pid shmget");
     pidsets=(pPidNums_t)shmat(shmidPid, NULL, 0);
     ERROR_CHECK(pidsets, (pPidNums_t) - 1, "pid shmat");
     pidsets->pidWriteA = pid;
     while(1){
         FD_ZERO(&rdset);
         FD_SET(STDIN_FILENO, &rdset);
         FD_SET(fdr, &rdset);
         ret = select(fdw + 1, &rdset, NULL, NULL, NULL);
         ERROR_CHECK(ret, -1, "select");
         printf("ret = %d\n", ret);
         if(FD_ISSET(STDIN_FILENO,&rdset)){
             memset(buf, 0, sizeof(buf));
             ret=read(STDIN_FILENO, buf, sizeof(buf));
             //        if(0==ret){
             //            printf("主动断开\n");
             //            break;
             //        }
             if(strcmp(buf,"\n")!=0){
                 write(fdw,buf,strlen(buf)-1);
                 ret = semop(semArrId,&sopp,1);
                 ERROR_CHECK(ret, -1, "semop1");
                 p->flag=2;
                 strcpy(p->buf,buf);
                 ret = semop(semArrId,&sopv,1);
                 ERROR_CHECK(ret, -1, "semop2");
             }
         }
         if(FD_ISSET(fdr, &rdset)){
             memset(buf, 0, sizeof(buf));
             ret=read(fdr, buf, sizeof(buf));
             ERROR_CHECK(ret, -1, "read");
             printf("ret = %d\n", ret);
             //        if(0==ret){
             //            printf("连接已断开\n");
             //            break;
             //        }
             ret = semop(semArrId, &sopp, 1);
             ERROR_CHECK(ret, -1, "semop1");
             p->flag = 1;
             strcpy(p->buf, buf);
             ret = semop(semArrId, &sopv, 1);
             ERROR_CHECK(ret, -1, "semop2");
             puts(buf);
         }
     }
     return 0;
 }

showB

#include <head.h>
 typedef struct pidnums{
     int pidWriteA;
     int pidWriteB;
     int pidShowA;
     int pidShowB;
 } pidNums_t,*pPidNums_t;
 typedef struct mymsgbuf{
     long mtype;
     char mtext[64];
 }MSG_t;
 pPidNums_t pidsets;
 void sigFunc2(int signum, siginfo_t *p, void *p1){
     printf("%d is coming\n", signum);
     kill(pidsets->pidWriteA, 10);
     kill(pidsets->pidWriteB, 10);
     kill(pidsets->pidShowA, 10);
     kill(pidsets->pidShowB, 10);
 }
 void sigFunc10(int signum, siginfo_t *p, void *p1){
     printf("%d is coming\n", signum);
     shmdt(pidsets);
     exit(0);
 }
 int main(int argc,char *argv[]) {
     struct sigaction act2;
     bzero(&act2,sizeof(act2));
     act2.sa_flags =S A_SIGINFO;
     act2.sa_sigaction = sigFunc2;
     int ret =s igaction(SIGINT,&act2,NULL);
     ERROR_CHECK(ret, -1, "sigaction 2");
     struct sigaction act10;
     bzero(&act10, sizeof(act10));
     act10.sa_flags = SA_SIGINFO;
     act10.sa_sigaction = sigFunc10;
     ret=sigaction(10, &act10, NULL);
     ERROR_CHECK(ret, -1, "sigaction");
     int msgid=msgget(1000, IPC_CREAT|0600);
     ERROR_CHECK(msgid, -1, "msgget");
     struct mymsgbuf msgInfo;
     int pid = getpid();
     int shmidPid = shmget(2000, 4096, IPC_CREAT|0600);
     ERROR_CHECK(shmidPid, -1, "pid shmget");
     pidsets=(pPidNums_t)shmat(shmidPid, NULL, 0);
     ERROR_CHECK(pidsets, (pPidNums_t) - 1, "pid shmat");
     pidsets->pidShowB = pid;
     while(1){
         bzero(&msgInfo, sizeof(msgInfo));
         ret = msgrcv(msgid, &msgInfo, sizeof(msgInfo), 0, 0);
         ERROR_CHECK(ret, -1, "msgrcv");
         if(msgInfo.mtype == 1){
             printf("%s\n\n", msgInfo.mtext);
         }
         if(msgInfo.mtype == 2){
             printf("%*s%s\n", 10, "", msgInfo.mtext);
         }
     }
     return 0;
 }

wirteB

#include <head.h>
 typedef struct pidnums{
     int pidWriteA;
     int pidWriteB;
     int pidShowA;
     int pidShowB;
 }pidNums_t, *pPidNums_t;
 pPidNums_t pidsets; 
 int fdr,fdw;
 int msgid;
 typedef struct mymsgbuf{
     long mtype;
     char mtext[64];
 } Msg_t,*pMsg_t;
 void sigFunc2(int signum, siginfo_t *p, void *p1){
     printf("%d is coming\n", signum);
     kill(pidsets->pidWriteA, 10);
     kill(pidsets->pidShowA, 10);
     kill(pidsets->pidShowB, 10);
     kill(pidsets->pidWriteB, 10);
 }
 void sigFunc10(int signum, siginfo_t *p, void *p1){
     printf("%d is coming\n", signum);
     close(fdr);
     close(fdw);
     shmdt(pidsets);
     msgctl(msgid, IPC_RMID,NULL);
     exit(0);
 }
 int main(int argc,char *argv[]) {
     ARGS_CHECK(argc, 3);
     struct sigaction act2;
     bzero(&act2, sizeof(act2));
     act2.sa_flags = SA_SIGINFO;
     act2.sa_sigaction =s igFunc2;
     int ret=sigaction(SIGINT, &act2, NULL);
     ERROR_CHECK(ret, -1, "sigaction 2");
     struct sigaction act10;
     bzero(&act10, sizeof(act10));
     act10.sa_flags =S A_SIGINFO;
     act10.sa_sigactio n= sigFunc10;
     ret=sigaction(10, &act10, NULL);
     ERROR_CHECK(ret, -1, "sigaction");
     fdw = open(argv[1], O_WRONLY);
     fdr = open(argv[2], O_RDONLY);
     printf("i am chat2 , fdr=%d fdw=%d\n", fdr, fdw);
     // B 和 showB 的消息队列
     char buf[128] = {0};
     fd_set rdset;
     msgid = msgget(1000, IPC_CREAT|0600);
     ERROR_CHECK(ret, -1, "msgget");
     struct mymsgbuf msgInfo;
     // pid 共享内存
     int pid = getpid();
     int shmidPid = shmget(2000, 4096, IPC_CREAT|0600);
     ERROR_CHECK(shmidPid, -1, "pid shmget");
     pidsets = (pPidNums_t)shmat(shmidPid, NULL, 0);
     ERROR_CHECK(pidsets, (pPidNums_t) - 1, "pid shmat");
     pidsets->pidWriteB = pid;
     while(1){
         FD_ZERO(&rdset);
         FD_SET(STDIN_FILENO, &rdset);
         FD_SET(fdr, &rdset);
         ret=select(fdr + 1, &rdset, NULL, NULL, NULL);
         ERROR_CHECK(ret, -1, "select");
         if(FD_ISSET(STDIN_FILENO, &rdset)){
             memset(buf, 0, sizeof(buf));
             ret = read(STDIN_FILENO, buf, sizeof(buf));
             //     if(0==ret){
             //         printf("主动断开\n");
             //         break;
             //     }
             if(strcmp(buf, "\n") != 0){
                 write(fdw,buf,strlen(buf) - 1);
                 msgInfo.mtype = 2;
                 strcpy(msgInfo.mtext, buf);
                 ret = msgsnd(msgid, &msgInfo, strlen(msgInfo.mtext), 0);
                 ERROR_CHECK(ret,-1,"msgsnd");
             }
         }
         if(FD_ISSET(fdr, &rdset)){
             memset(buf, 0, sizeof(buf));
             ret=read(fdr, buf, sizeof(buf));
             ERROR_CHECK(ret, -1, "read");
             //     if(0==ret){
             //         printf("连接已断开\n");
             //         break;
             //     }
             if(strlen(buf) != 0){
                 puts(buf);
                 msgInfo.mtype = 1;
                 strcpy(msgInfo.mtext, buf);
                 ret = msgsnd(msgid, &msgInfo, strlen(msgInfo.mtext), 0);
                 ERROR_CHECK(ret, -1, "msgsnd");
             }
         }
     }
     close(fdr);
     close(fdw);
     return 0;
 }
相关文章
|
3月前
|
Ubuntu Linux
【Linux】详解信号产生的方式
【Linux】详解信号产生的方式
|
3月前
|
Unix Linux
【Linux】详解信号的分类&&如何自定义信号的作用
【Linux】详解信号的分类&&如何自定义信号的作用
|
1月前
|
安全 小程序 Linux
Linux中信号是什么?Ctrl + c后到底为什么会中断程序?
信号在进程的学习中是一个非常好用的存在,它是软件层次上对中断机制的一种模拟,是异步通信方式,同时也可以用来检测用户空间到底发生了什么情况,然后系统知道后就可以做出相应的对策。
|
1月前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
|
1月前
|
存储 NoSQL Unix
【Linux】进程信号(下)
【Linux】进程信号(下)
28 0
|
1月前
|
安全 Linux Shell
【Linux】进程信号(上)
【Linux】进程信号(上)
29 0
|
2月前
|
Linux Shell
蓝易云 - 【Linux-Day8- 进程替换和信号】
这两个概念在Linux系统编程和shell脚本编写中都非常重要,理解它们可以帮助你更好地理解和控制Linux系统的行为。
32 9
|
2月前
|
Linux
【Linux】进程信号_1
【Linux】进程信号_1
16 0
|
3月前
|
存储 Unix Linux
[Linux打怪升级之路]-信号的产生
[Linux打怪升级之路]-信号的产生
[Linux打怪升级之路]-信号的产生
|
3月前
|
Unix Linux C语言