1. 程式人生 > >Linux signals(一)理論、C語言捕獲訊號並處理

Linux signals(一)理論、C語言捕獲訊號並處理

首先需要知道signals和interrupt是不同的。
signal屬於程序通訊機制的一種實現方式
(還有的實現為:Pipes、Sockets
其中Sockets又可分為: System V IPC Mechanisms、Message Queues、Semaphores、Shared Memory)
關於程序間通訊,具體參見:Chapter 5
Interprocess Communication Mechanisms

而具體的不同,別人的回答是:

Interrupts can be viewed as a mean of communication between the CPU and the OS kernel. Signals can be viewed as a mean of communication between the OS kernel and OS processes.

Interrupts may be initiated by the CPU (exceptions -e.g.: divide by zero, page fault), devices (hardware interrupts -e.g.: input available), or by a CPU instruction. They are eventually managed by the CPU, which “interrupts” the current task,and invokes an 0S-kernel provided ISR/interrupt handler

Signals may be initiated by the OS kernel(下面的例項也揭示了這一點), or by a process( kill() ). They are eventually managed by the OS kernel, which delivers them to the target thread/process, invoking either a generic action (ignore, terminate, terminate and dump core) or a process-provided signal handler.

  • SIGKILL與SIGSTOP是兩個唯一不能忽略也不能捕獲的訊號

C語言捕獲訊號並處理

第一步:向核心註冊

the process has to register a signal handling function to the kernel.

原型是:c void <signal handler func name> (int sig)

第二步:獲得signal handler

To get the signal handler function registered to the kernel, the signal handler function pointer is passed as second argument to the ‘signal’ function

原型是:c void (*signal(int signo, void (*func )(int)))(int);
簡單化:c sigfunc *signal(int, sigfunc*);

例項一:簡單捕獲訊號並處理

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
  if (signo == SIGINT)
    printf("received SIGINT\n");
}

int main(void)
{
  if (signal(SIGINT, sig_handler) == SIG_ERR)
  printf("\ncan't catch SIGINT\n");
  //必須加上死迴圈(或者用掛起)來讓訊號能被程序接收
  while(1) 
    sleep(1);
  return 0;
}
//注意,當前終端用ctrl+c模擬,
//需要終止時,另一個終端使用 ps aux檢視程序號,然後用 kill -9 程序號
//來殺死

還值得一提的是,這兒用while(1) sleep(1)
比用單純的while死迴圈要好,因為直接while可能會消耗cpu的大部分資源,導致電腦很慢。

On a side note, the use of function sleep(1) has a reason behind. This function has been used in the while loop so that while loop executes after some time (ie one second in this case). This becomes important because otherwise an infinite while loop running wildly may consume most of the CPU making the computer very very slow

例項二:自定義訊號

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_handler(int signo)
{
    if (signo == SIGUSR1)
        printf("received SIGUSR1\n");
    else if (signo == SIGKILL)
        printf("received SIGKILL\n");
    else if (signo == SIGSTOP)
        printf("received SIGSTOP\n");
}

int main(void)
{
    if (signal(SIGUSR1, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGUSR1\n");
    if (signal(SIGKILL, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGKILL\n");
    if (signal(SIGSTOP, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGSTOP\n");
    // A long long wait so that we can easily issue a signal to this process
    while(1) 
        sleep(1);
    return 0;
}

另一個終端執行:

$ kill -USR1 程序號

輸出:

$ ./sigfunc

can't catch SIGKILL

can't catch SIGSTOP
received SIGUSR1