1

linux进程间通信-信号

 1 month ago
source link: https://blog.51cto.com/u_16704018/10680563
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
linux进程间通信-信号_linux进程间通信之信号

信号(Signal)

信号的基本概念

信号是一种异步的、非阻塞的通信机制,用于通知接收进程某个事件已经发生。例如,SIGINT信号通常由 Ctrl+C触发,用于终止进程。

信号(Signal)也叫“用户态中断”,用于异步通知进程某个事件的发生,每个信号都有一个唯一的编号和一个对应的处理动作。当某个信号发生时,内核会向相应的进程发送该信号,并触发预设的信号处理函数或执行默认操作。

信号通常用于简单的事件通知,如终止进程、暂停执行等,而不适合用于复杂的数据传输任务。

信号的一些特点

  1. 信号的异步性: 信号在任何时候都可能被触发,这意味着它们是异步的。无法预测信号的确切发生时间,因此也无法保证信号处理的顺序。
  2. 信号阻塞: 进程可以选择阻塞某些信号,这意味着在阻塞期间,这些信号不会被传递或处理,这破坏了信号的及时性。
  3. 信号丢失: 如果一个进程在很短的时间内连续收到相同的信号,可能会导致信号丢失,因为Linux内核默认只会将该信号传递一次。
  4. 信号与进程状态: 信号的传递和处理还依赖于进程的状态。如果进程处于不可中断的睡眠状态,信号可能无法立即传递。
  5. 缺乏流量控制: 信号机制没有内置的流量控制,无法控制信号的发送速率,这可能导致信号的丢失或延迟。
  6. 信号的有限行为: 信号处理函数中不应该执行可能导致进程状态不一致的操作,如打开文件、分配内存等。信号处理函数应该尽可能快地执行完。

信号的种类

Linux系统中定义了许多种类的信号,每个信号都有其特定的含义和用途。常见的信号包括:

  1. SIGINT(中断信号,通常由Ctrl+C产生):用于终止前台进程。
  2. SIGQUIT(退出信号,通常由Ctrl+\产生):用于终止进程并产生core文件。
  3. SIGTERM(终止信号):用于正常终止进程。
  4. SIGKILL(强制终止信号):强制终止进程,该信号不能被捕获或忽略。
  5. SIGSTOP(暂停信号):暂停进程的执行。
  6. SIGCONT(继续信号):恢复被暂停的进程执行。

此外,还有许多其他类型的信号,如SIGUSR1SIGUSR2等用户自定义信号,以及SIGHUPSIGCHLDSIGPIPESIGALRM等系统定义的信号。

信号的处理方式

Linux内核提供了三种处理信号的方式:

  1. 忽略信号:进程可以选择忽略某个信号,当该信号到达时,系统会自动忽略它。但是有些信号(如SIGKILLSIGSTOP)不能被忽略。
  2. 捕捉信号:进程可以注册信号处理函数,当信号到达时,内核会调用相应的处理函数来处理该信号。这使得进程能够在接收到信号时执行特定的操作,如清理资源、保存数据等。
  3. 默认处理方式:对于大多数信号,系统都会提供一个默认的处理方式。例如,SIGTERM的默认处理方式是终止进程。如果进程没有为某个信号指定处理函数,那么当该信号到达时,系统会执行默认的操作。

需要注意的是,如果一个用户进程捕获了SIGINT信号(通常是通过按下Ctrl+C产生的),并且为这个信号注册了一个自定义的处理函数,那么当SIGINT信号发生时,用户进程将执行这个自定义的处理函数,而不是Linux内核默认的终止进程行为。

此外,还有一些信号是不能被用户态程序捕获或忽略的,例如SIGKILLSIGSTOP。这些信号用于强制终止或暂停进程,并且只能由操作系统内核处理。

在C语言中,可以使用 signal()函数或 sigaction()函数来设置信号处理函数。sigaction()函数提供了更多的控制选项,并且是可移植的,推荐在编程中使用。

信号的发送与接收

信号的发送可以通过多种方式实现,如通过终端按键产生信号(如Ctrl+C)、调用系统函数向进程发送信号(如kill()函数、raise()函数)、由软件条件产生信号(如alarm()函数和SIGALRM信号)以及硬件异常产生信号等。当进程接收到信号时,会根据预设的信号处理函数或默认操作来响应。

实验:处理 SIGINT信号

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

void handle_sigint(int sig) {
    printf("Caught signal %d\n", sig);
}

int main() {
    // 设置SIGINT信号的处理函数
    signal(SIGINT, handle_sigint);

    while (1) {
        printf("Waiting for SIGINT...\n");
        sleep(1);
    }

    return 0;
}

实验结果 

linux进程间通信-信号_linux进程间通信之信号_02

实验解释:

当用户运行这个程序时,它会进入一个无限循环,并定期打印消息表明它正在等待 SIGINT 信号。当用户按下 Ctrl+C 时,会向前台进程组发送 SIGINT 信号。由于程序已经通过 signal 函数注册了 SIGINT 的自定义处理函数 handle_sigint,因此程序不会终止,而是调用 handle_sigint 函数。
在 handle_sigint 函数中,程序简单地打印出接收到的信号编号,然后返回。由于程序没有执行任何退出操作,它会在 sleep 调用结束后继续执行,再次打印消息,并等待下一个 SIGINT 信号。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK