day_12_信号处理、进程间通信

来源:互联网 发布:淘宝贷款条件是什么 编辑:程序博客网 时间:2024/05/29 04:44

    • 一信号的处理
      • 1 发送信号的系统函数
        • 1raise
          • sleep
          • usleep
          • pause
        • 2alarm
      • 2 信号集的基本概念和基本操作
        • 1基本概念
        • 2基本操作
          • sigemptyset - 清空信号集
          • sigfillset - 填满信号集
          • sigaddset - 添加信号到信号集中
          • sigdelset - 删除信号集中的信号
          • sigismember - 判断信号是否存在
      • 3 信号的屏蔽
        • 1sigprocmask
        • 2sigpending
      • 4 计时器
      • 5 扩展
        • 1sigaction
        • 2sigqueue
    • 二进程间的通信技术
      • 1 基本概念
      • 2 通信方式

一、信号的处理

1.1 发送信号的系统函数

(1)raise()

#include <signal.h>int raise(int sig);
功能:
主要用于给当前正在调用的线程/线程发送参数指定的信号,对于单线程的程序来说,等价于kill(getpid(), sig);
返回值:
success —- 0,error —- 非0;
sleep()
#include <unistd.h>unsigned int sleep(unsigned int seconds);
功能:
主要用于使得当前正在调用的线程进入睡眠状态,直到参数指定的秒数睡够了,或者一个不能被忽略的信号到达了;
返回值:
如果参数指定的秒数过去了,则返回0,否则返回还没有来得及睡的秒数,也就是剩余的秒数;
usleep()
#include <unistd.h>int usleep(useconds_t usec);  //useconds = unsigned int;
功能:
主要用于使得当前正在调用的线程睡眠参数指定的微秒;
pause()
#include <unistd.h>int pause(void);
功能:
主要用于是的当前正在调用的进程或线程暂停程序的执行,等待信号的到来;
返回值:
只有当信号被捕获时返回-1,并设置errno为EINTR;

(2)alarm()

#include <unistd.h>unsigned int alarm(unsigned int seconds);

功能:
  主要用于在进过参数指定的秒数之后,给当前正在调用的进程发送SIGALRM信号;
  每次重新设置闹钟之后都会取消之前的闹钟,当参数为0时,专门用于取消闹钟;

返回值:
  如果之前没有闹钟则返回0,否则返回之前闹钟剩余的秒数;


1.2 信号集的基本概念和基本操作

(1)基本概念

  信号集本质上就是若干个信号组成的集合。

思考:
  请问采用最节省内存空间的方式设计信号集的数据类型,如何设计?

分析:
  int arr[64];   => 4*64 = 256B
  short arr[64];   => 2*64 = 128B
  char arr[64];   => 1*64 = 64B
采用每一个二进制位来代表一个信号,使用1表示有该信号,使用0表示没有该信号;=> 8B
  … 0010 0011   => 存在信号1、信号2、信号6

结论:
  操作系统内部使用数据类型:sigset_t表示信号集的数据类型,该数据类型的大小是:128B;

typedef struct{    unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];} __sigset_t; typedef __sigset_t sigset_t

(2)基本操作

sigemptyset() - 清空信号集
#include <signal.h>int sigemptyset(sigset_t *set);
sigfillset() - 填满信号集
#include <signal.h>int sigfillset(sigset_t *set);
sigaddset() - 添加信号到信号集中
#include <signal.h>int sigaddset(sigset_t *set, int signum);
sigdelset() - 删除信号集中的信号
#include <signal.h>int sigdelset(sigset_t *set, int signum);
sigismember() - 判断信号是否存在
#include <signal.h>int sigismember(const sigset_t *set, int signum);

返回值:
  信号存在返回1,信号不存在返回0,出错返回-1;


1.3 信号的屏蔽

  在某些特殊程序的执行过程中,可能不允许被信号打断,此时就需要使用信号的屏蔽技术来解决该问题;

(1)sigprocmask()

#include <signal.h>/* Prototype for the glibc wrapper function */int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:
主要用于检查 / 修改即将屏蔽的信号集;
参数:
第一个参数:具体的屏蔽方式;
  SIG_BLOCK - 使用当前屏蔽集 + 参数set屏蔽集
        - ABC + CDE(set) =>ABCDE
  SIG_UNBLOCK - 使用当前屏蔽集 - 参数set屏蔽集
        - ABC - CDE(set) => AB
  SIG_SETMASK - 使用参数set屏蔽集替换当前屏蔽集
        - ABC CDE(set) => CDE
第二个参数:信号集类型的指针,用于指定新的信号集;
第三个参数:信号集类型的指针,用于带出之前屏蔽的信号集;
      如果不想带出之前的屏蔽集,该参数给NULL即可;

注意:
  信号的屏蔽并不是删除信号,而是相当于用一个隔板把信号档起来,对于可靠信号来说,产生了多少次,则在隔板的另一侧会排队等待多少个,而对于不可靠信号来说,无论产生了多少次,在隔板的另一侧只有一个信号排队等待,当信号的屏蔽解除时,相当于将隔板移开,只要进程不结束,则全部依次处理;

(2)sigpending()

#include <signal.h>int sigpending(sigset_t *set);
功能:
主要用于获取信号屏蔽期间来过但没来得及处理的信号集,通过参数set返回;

1.4 计时器

  在linux系统中,操作系统会为每一个进程管理3种计时器,分别为:真实计时器、虚拟计时器以及实用计时器,一般都使用真实计时器进行计时;

#include <sys/time.h>int getitimer(int which, struct itimerval *curr_value);int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
功能:
主要用于获取 / 设置计时器的参数信息;
参数:
第一个参数:计时器的类型;
  ITIMER_REAL - 真实计时器,产生SIGALRM信号
         - 统计进程消耗的真实时间
  ITIMER_VIRTUAL - 虚拟计时器,产生SIGVTALRM信号
          - 统计进程在用户态下消耗的时间(了解)
  ITIMER_PROF - 实用计时器,产生SIGPROF信号
         - 统计进程在用户态和内核态消耗的总时间
第二个参数:结构体指针,用于指定计时器的新值;
struct itimerval{    struct timeval it_interval; /* 间隔时间 */    struct timeval it_value;    /* 开始时间 */};struct timeval{    time_t      tv_sec;         /* 秒 */    suseconds_t tv_usec;        /* 微秒 */};

   第三个参数:结构体指针,用于带出设置之前的旧值;


1.5 扩展

(1)sigaction()

#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
功能:
主要用于设置信号的处理方式,signal()的增强版;
参数:
第一个参数:具体的信号值 / 信号名称;(SIGKILL和SIGSTOP除外)
第二个参数:结构体指针,设置指定信号新的处理方式;
struct sigaction{    void     (*sa_handler)(int);    void     (*sa_sigaction)(int, siginfo_t *, void *);    sigset_t   sa_mask;    int        sa_flags;    void     (*sa_restorer)(void);};struct siginfo_t{    int si_signo;  /* 信号值 */    ...}

   第三个参数:结构体指针,获取指定信号原来的处理方式;

(2)sigqueue()

#include <signal.h>int sigqueue(pid_t pid, int sig, const union sigval value);
功能:
主要用于向指定的进程发送指定的信号,还可以带一个附加数据;
参数:
第一个参数:指定进程的进程号;
第二个参数:具体的信号值 / 信号名称,类似kill();
  0 - - - - - 测试指定的进程是否存在
第三个参数:联合类型,
union sigval{    int   sival_int;    void *sival_ptr;};

… …

二、进程间的通信技术

2.1 基本概念

  两个 / 多个进程之间的信息交互,就叫做进程间的通信;

2.2 通信方式

  1. 文件
  2. 信号
  3. 管道
  4. 共享内存
  5. 消息队列(重点)
  6. 信号量集
  7. 网络(重点)
    … …

其中4、5、6通信方式统称为XSI IPC通信方式(X/open System Interface Inter-Process Communication)

练习:
  尝试查询sigaction()的用法;

明日预报:
(1)进程间的通信技术;