Linux信号集

  1.信号集概念

  信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。

  既然是一个集合,就需要对集合进行添加/删除等操作。

  int sigemptyset(sigset_t *set); 将set集合置空

  int sigfillset(sigset_t *set); 将所有信号加入set集合

  int sigaddset(sigset_t *set,int signo); 将signo信号加入到set集合

  int sigdelset(sigset_t *set,int signo); 从set集合中移除signo信号

  int sigismember(const sigset_t *set,int signo); signo判断信号是否存在于set集合中


   2.信号集的操作

    1>sigprocmask(查询或设置信号掩码)
相关函数 

signal,sigaction,sigpending,sigsuspend

表头文件 
#include<signal.h>

定义函数 
int sigprocmask(int how,const sigset_t *set,sigset_t * oldset);

函数说明 
sigprocmask()可以用来改变目前的信号遮罩,其操作依参数how来决定
SIG_BLOCK 新的信号遮罩由目前的信号遮罩和参数set 指定的信号遮罩作联集
SIG_UNBLOCK 将目前的信号遮罩删除掉参数set指定的信号遮罩
SIG_SETMASK 将目前的信号遮罩设成参数set指定的信号遮罩。
如果参数oldset不是NULL指针,那么目前的信号遮罩会由此指针返回。

返回值 
执行成功则返回0,如果有错误则返回-1。

错误代码 
EFAULT 参数set,oldset指针地址无法存取。
EINTR 此调用被中断


注:如果将set设为一空指针,那么进程的信号掩码将不会改变,这时how的位也是没有以意义的。


下面给出一个例子,用来说明这个函数

功能是打印调用进程的信号掩码中的信号的名称

#include <stdio.h>
#include <signal.h>
#include <string.h>void pr_mask()
{sigset_t sigset;if(sigprocmask(0, NULL, &sigset)<0){printf("sigprocmask error");exit(0);}if(sigismember(&sigset, SIGINT))printf("SIGINT \n");if(sigismember(&sigset, SIGTERM)){printf("SIGTERM \n");exit(0);}}int main()
{char buffer1[100],buffer2[100];int i;if(signal(SIGINT, &pr_mask)==-1){printf("Couldn't register signal hanlder for SIGINT!\n");exit(1);}if(signal(SIGTERM, &pr_mask)==-1){printf("Couldn't register signal hanlder for SIGTERM!\n");exit(1);}printf("Pid of This Process : %d \n",getpid());for(;;){printf("Please input:\n");fgets(buffer1, sizeof(buffer1),stdin);for(i=0;i<100;i++){if(buffer1[i]>=97&&buffer1[i]<=122)buffer2[i]=buffer1[i]-32;elsebuffer2[i]=buffer1[i];}printf("Your input is: %s \n",buffer2);}exit(0);
}

2>sleep(让进程暂停执行一段时间)

相关函数 
signal,alarm

表头文件 
#include<unistd.h>

定义函数 
unsigned int sleep(unsigned int seconds);

函数说明 
sleep()会令目前的进程暂停,直到达到参数seconds 所指定的时间,或是被信号所中断。

返回值 
若进程暂停到参数seconds 所指定的时间则返回0,若有信号中断则返回剩余秒数。


3>sigpending(查询被搁置的信号)

相关函数 
signal,sigaction,sigprocmask,sigsuspend

表头文件 
#include<signal.h>

定义函数 
int sigpending(sigset_t *set);

函数说明 
sigpending()会将被搁置的信号集合由参数set指针返回。

返回值执 
行成功则返回0,如果有错误则返回-1。

错误代码 
EFAULT 参数set指针地址无法存取
EINTR 此调用被中断。


下面给出一个实例,说明其用法:

#include <signal.h>
#include <stdio.h>static void sig_quit(int);int main()
{sigset_t newmask, oldmask, pendmask;if(signal(SIGQUIT,&sig_quit)==-1){printf("Couldn't register signal hanlder for SIGQUIT!\n");exit(1);}sigemptyset(&newmask);sigaddset(&newmask,SIGQUIT);if(sigprocmask(SIG_BLOCK, &newmask, &oldmask)<0){printf("SIG_BLOCK error.\n");exit(2);}sleep(5);if(sigpending(&pendmask)<0){printf("sigpending  error.\n");exit(3);}if(sigismember(&pendmask,SIGQUIT))printf("SIGQUIT pending \n");if(sigprocmask(SIG_SETMASK, &oldmask, NULL)<0){printf("SIG_SETMASK  error.\n");exit(4);}printf("SIGQUIT unblocked.\n");sleep(5);exit(0);
}static void sig_quit(int signum)
{printf("catch SIGQUIT.\n");if(signal(SIGQUIT, SIG_DFL)==-1)printf("Couldn't reset SIGQUIT!\n");return;
}

4>sigsuspend函数

函数原型:

#include  <signal.h>
int sigsuspend(const sigset_t *mask);

作用:

用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。
也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接收到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。

返回值:
sigsuspend返回后将恢复调用之前的的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR.


下面给出一个例子,使用sigsuspend函数使进程挂起等待某个全程变量

#include <signal.h>
#include <stdio.h>int quitflag=0;int main()
{void sig_int(int);sigset_t newmask, oldmask, zeromask;if(signal(SIGINT,&sig_int)==-1){printf("Couldn't register signal hanlder for SIGINT!\n");exit(1);}if(signal(SIGQUIT,&sig_int)==-1){printf("Couldn't register signal hanlder for SIGQUIT!\n");exit(2);}sigemptyset(&zeromask);sigemptyset(&newmask);sigaddset(&newmask,SIGQUIT);if(sigprocmask(SIG_BLOCK, &newmask, &oldmask)<0){printf("SIG_BLOCK  error.\n");exit(3);}while(quitflag==0)sigsuspend(&zeromask);printf("process wake up.\n");quitflag=0;if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)exit(0);
}void sig_int(int signum)
{if(signum==SIGINT)printf("\n interrupt \n");else if (signum==SIGQUIT){printf("catch SIGQUIT \n");quitflag=1;}return ;
}

发送信号

1. 函数说明:
  kill和raise是用来发送信号的:
  kill把信号发送给进程或进程组;
  raise把信号发送给(进程)自身.
  他们的原型如下:
  #include 
  int kill(pid_t pid, int signo);
  int raise(int signo);
  成功则返回0, 出错则返回-1
  从原型上可以看出, raise函数是可以通过kill实现的.
  raise(signo);
  等价于:
  kill(getpid(), signo);


2. pid参数:
  kill函数中的pid参数, 它有以下4种情况:
  pid > 0: 将该信号发送给进程ID为pid的进程. 
  pid == 0: 将该信号发送给与发送进程属于同一进程组的所有进程(不包括内核进程和init进程). 此时, 发送进程必须具有向这些进程发送信号的权限. 
  pid < 0: 将该信号发给其进程组ID等于pid绝对值的所有进程(不包括内核进程和init进程). 此时, 发送进程必须具有向这些进程发送信号的权限. 
  pid == -1: 将该信号发送给发送进程有权限向它们发送信号的系统上的所有进程.(不包括内核进程和init进程).

3. signo参数:
  POSIX.1将编号为0的信号定义为空信号. 如果signo参数是0, 则kill仍执行正常的错误检查, 但不发送信号. 这被用来确定一个进程是否存在.


下面给出两个例子说明这两个函数的使用方法:

1.raise函数的使用

#include <stdio.h>
#include <signal.h>void inthandler(int signum);
void continuehandler(int signum);
void terminatehandler(int signum);int main()
{char buffer[100];if(signal(SIGINT,&inthandler)==-1){printf("Couldn't register signal hanlder for SIGINT!\n");exit(1);}if(signal(SIGTSTP, &inthandler)==-1){printf("Couldn't register signal hanlder for SIGTSTP!\n");exit(2);}if(signal(SIGCONT, &continuehandler)==-1){printf("Couldn't register signal hanlder for SIGCONT!\n");exit(3);}if(signal(SIGTERM, &terminatehandler)==-1){printf("Couldn't register signal hanlder for SIGINT!\n");exit(4);}printf("Pid of This Process : %d \n",getpid());for(;;){printf("Please input:\n");fgets(buffer, sizeof(buffer),stdin);if(strcmp(buffer,"int\n")==0)raise(SIGINT);else if(strcmp(buffer,"stop\n")==0)raise(SIGTSTP);else if(strcmp(buffer,"continue\n")==0)raise(SIGCONT);else if(strcmp(buffer,"quit\n")==0)raise(SIGTERM);elseprintf("Your input is: %s \n",buffer);}exit(0);
}void inthandler(int signum)
{printf("catch signal %d \n",signum);
}void continuehandler(int signum)
{printf("Continue code.\n");
}void terminatehandler(int signum)
{printf("signal SIGTERM \n");exit(0);
}

2.kill函数的使用

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int usr_interrupt=0;void synch_signal(int signum)
{usr_interrupt=1;
}void child_function()
{printf(" I'm child process. My pid is %d \n",getpid());sleep(5);kill(getppid(),SIGUSR1);puts("Good bye! \n");exit(0);
}int main()
{struct sigaction usr_action;sigset_t block_mask;pid_t child_id;sigfillset(&block_mask);usr_action.sa_handler=synch_signal;usr_action.sa_mask=block_mask;usr_action.sa_flags=0;sigaction(SIGUSR1, &usr_action,NULL);child_id=fork();if(child_id==0)child_function();while(!usr_interrupt);puts("That's all!");return 0;
}

Linux C编程--进程间通信(IPC)3--信号集和发送信号介绍相关推荐

  1. linux 服务器间通信,Linux 下的进程间通信:套接字和信号 | Linux 中国

    原标题:Linux 下的进程间通信:套接字和信号 | Linux 中国 学习在 Linux 中进程是如何与其他进程进行同步的. -- Marty Kalin 本篇是 Linux 下(IPC)系列的第三 ...

  2. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  3. 信号 信号的注册 信号的发送 信号的阻塞

    目录 信号 信号的阻塞 信号的注册 信号的发送 信号   信号是信息的载体,怎么理解呢?就类似于烽火戏诸侯的周幽王点燃了烽火台发出了这个信号,然后各路诸侯收到了这个信号就过来救驾勤王了.   进程也是 ...

  4. Linux C编程--进程间通信(IPC)1--进程间通信机制概述

    linux下进程间通信的几种主要手段简介: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它 ...

  5. Linux网络编程--进程间通信(一)

    进程间通信简介(摘自<Linux网络编程>p85) AT&T 在 UNIX System V 中引入了几种新的进程通讯方式,即消息队列( MessageQueues),信号量( s ...

  6. Linux系统编程—进程间通信—信号量

    信号量 信号量是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用.在进入一个关键代码段之前,线程必须获取一个信号量:一旦该关键代码段完成了,那么该线程必须释放信号量.其它想 ...

  7. Linux(服务器编程):25---epoll复用技术实现统一处理信号事件源

    一.统一信号处理事件源概述 信号是一种异步事件:信号处理函数和程序的主循环是两条不同的执行路线.显然,信号处理函数需要尽可能快地执行完毕,以确保该信号不被屏蔽(为了避免一些竞态条件,信号在处理期间,系 ...

  8. Linux C编程--进程间通信(IPC)5--System V IPC 机制1--消息队列

    System V IPC 机制 1.基本概念 IPC对象一经创建,系统内核即为该对象分配相关的数据结构.为方便对IPC对象的管理,Linux提供了专门的IPC控制命令,主要包括查看IPC对象信息的ip ...

  9. Linux C编程--进程间通信(IPC)4--管道详解

    linux管道 管道相关内容的简介 管道是单向的字节流,它将某个进程的标准输出连接到另一个进程的标准输入.管道和有名管道是最早的进程间通信机制之一,管道可用于具有亲缘关系进程间的通信,有名管道克服了管 ...

最新文章

  1. java exchange发邮件_java发送exchange邮件问题
  2. MFC,ADO方式实现数据库操作
  3. href 里面 链接前面加/与不加的区别?(绝对路径与相对路径)
  4. 面试官:能说下 SpringBoot 启动原理吗?
  5. 【图文详解】JAVA字面量和变量
  6. 汇新杯┃拼多多黄峥:普通的创业者,不普通的朋友圈_创成汇
  7. 抓取手机https_python爬虫入门02:教你通过 Fiddler 进行手机抓包
  8. 数据库选型入门必读:如何在眼花缭乱的产品中挑出最适合业务的?
  9. 容器、微服务和互联网架构浅谈
  10. Python机器学习:梯度下降法003线性回归中的梯度下降法
  11. 郭卓惺:互动课堂的搭建实例及相关领域应用
  12. 基于Ajax的模糊查询输入控件(补充)
  13. Mac M1运行matlab卡,解决办法
  14. 21-04-08 cms日志分析
  15. arccatalog点要素显示不完_改变人际关系核心要素,不讨好不献媚,牢记这3点,受益一生...
  16. O2O电子商务 营销模式
  17. java世界杯hashmap,集合框架
  18. 卡贴机被“全面封杀”?苹果关闭有锁iPhone的ICCID激活服务
  19. python头像截取_身份证头像截取 - osc_8plez0fy的个人空间 - OSCHINA - 中文开源技术交流社区...
  20. 前端开发:a标签的使用

热门文章

  1. Android Studio问题集锦
  2. 解决eclipse编译的几种方法
  3. Cisco访问控制列表配置指南
  4. 周日21点50:关注电子阅读的大潮到来
  5. [推荐]在线测试你的网速
  6. 测试1111111111111111111
  7. MySQL存储过程的创建及调用
  8. poj-1031-fence(不是我写的,我只是想看着方便)
  9. cacti忘记密码怎么办
  10. ThinkPHP使用分组详细介绍(十七)