天天看點

day_12_信号處理、程序間通信

    • 一信号的處理
      • 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[( / ( * 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)程序間的通信技術;

繼續閱讀