三二互联专业提供速度最快最稳定的美国服务器、香港服务器。中美直连,亚洲优化![ 代理登陆 ] [ 付款方式 ] [ 找回密码 ][ 电子协议责任书 ]
硬件资源保障

采用高配品牌服务器

主流强悍CPU配置

确保服务高速稳定运行

中美直连线路

中美直连亚洲优化

采用中国CN2骨干网络

保证速度飞快稳定高效

进程的信号处理函数如何定义?

美国、香港服务器

进程的信号处理函数如何定义?

08-19   来源:

 在 Linux 系统中,进程的信号处理函数通过系统调用注册,用于自定义进程收到特定信号时的行为(替代内核默认处理)。定义信号处理函数的核心是函数原型符合标准,并通过 signal() 或 sigaction() 等系统调用将函数与目标信号绑定。以下是详细方法:

一、信号处理函数的原型(必须遵守)
信号处理函数的原型有严格规定,必须为:
 
c
运行
void handler(int signum);
 
参数 signum:接收的信号编号(如 SIGINT 对应 2,SIGUSR1 对应 10),用于区分不同信号。
返回值:void(无返回值)。
 
示例:定义一个处理 SIGINT(Ctrl+C 触发)的函数:
 
c
运行
#include
#include
 
// 信号处理函数:收到信号时打印信号编号
void sigint_handler(int signum) {
    printf("收到信号 %d(SIGINT),不退出程序!\n", signum);
}
二、注册信号处理函数(绑定信号与函数)
定义函数后,需通过系统调用将其与目标信号绑定,常用方法有两种:
方法 1:使用 signal() 函数(简单但功能有限)
signal() 是早期的信号注册函数,接口简单,适合基础场景。
 
函数原型:
 
c
运行
#include
void (*signal(int signum, void (*handler)(int)))(int);
 
参数 1:signum 为目标信号(如 SIGINT、SIGUSR1)。
参数 2:handler 为信号处理函数的指针,或特殊值:
SIG_IGN:忽略该信号。
SIG_DFL:恢复默认处理行为。
返回值:成功返回之前的处理函数指针,失败返回 SIG_ERR。
 
示例:将 sigint_handler 绑定到 SIGINT 信号:
 
c
运行
int main() {
    // 注册SIGINT信号的处理函数
    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        perror("signal注册失败");
        return 1;
    }
 
    // 循环等待信号(避免程序退出)
    while (1) {
        printf("等待信号...(按Ctrl+C测试)\n");
        sleep(1);
    }
    return 0;
}
 
特点:
 
优点:用法简单,适合快速注册信号处理。
缺点:行为在不同系统中可能不一致(如某些系统会自动重置信号处理为默认值),不支持传递额外信号信息。
方法 2:使用 sigaction() 函数(推荐,功能全面)
sigaction() 是 POSIX 标准的信号注册函数,功能更强大,支持设置信号处理的细节(如是否阻塞其他信号、是否传递信号上下文)。
 
函数原型:
 
c
运行
#include
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
 
参数 1:signum 为目标信号。
参数 2:act 是结构体指针,定义新的信号处理方式(可为 NULL 表示不修改)。
参数 3:oldact 用于保存旧的信号处理方式(可为 NULL 表示不获取)。
返回值:成功返回 0,失败返回 - 1。
 
核心结构体 struct sigaction:
 
c
运行
struct sigaction {
    void (*sa_handler)(int);          // 信号处理函数(与signal()的handler相同)
    sigset_t sa_mask;                 // 处理信号时临时阻塞的信号集
    int sa_flags;                     // 信号处理的标志位(如SA_RESTART重启被中断的系统调用)
    void (*sa_sigaction)(int, siginfo_t *, void *);  // 高级处理函数(需配合SA_SIGINFO标志)
};
 
示例:用 sigaction() 注册 SIGINT 处理函数,设置额外参数:
 
c
运行
#include
#include
#include
 
void sigint_handler(int signum) {
    printf("收到信号 %d(SIGINT),不退出程序!\n", signum);
}
 
int main() {
    struct sigaction act;
 
    // 初始化sigaction结构体
    act.sa_handler = sigint_handler;  // 指定处理函数
    sigemptyset(&act.sa_mask);        // 清空阻塞信号集(处理时不额外阻塞其他信号)
    act.sa_flags = 0;                 // 无特殊标志
 
    // 注册SIGINT信号
    if (sigaction(SIGINT, &act, NULL) == -1) {
        perror("sigaction注册失败");
        return 1;
    }
 
    // 循环等待信号
    while (1) {
        printf("等待信号...(按Ctrl+C测试)\n");
        sleep(1);
    }
    return 0;
}
 
特点:
 
优点:行为标准统一,支持设置阻塞信号集、重启系统调用等高级功能,推荐优先使用。
支持 sa_sigaction 高级处理函数(需设置 sa_flags = SA_SIGINFO),可获取信号发送者 PID、信号值等详细信息。
三、信号处理函数的注意事项(关键)
函数内操作限制
信号处理函数运行在 “信号上下文” 中,应避免调用非异步安全(non-async-signal-safe) 的函数(如 printf、malloc、fopen 等),可能导致死锁或数据损坏。
安全函数列表:write、_exit、sigprocmask 等(详见 man 7 signal-safety)。
示例:用 write 替代 printf 更安全:
c
运行
void sigint_handler(int signum) {
    const char* msg = "收到SIGINT信号\n";
    write(STDOUT_FILENO, msg, strlen(msg));  // write是异步安全的
}
 
信号重入问题
若同一信号在处理过程中再次发生(未设置 SA_RESETHAND 标志),可能导致处理函数重入,需确保函数是 “可重入的”(如不修改全局变量,或使用原子操作)。
信号掩码与阻塞
通过 sa_mask 可设置处理信号时临时阻塞的信号(如处理 SIGINT 时阻塞 SIGQUIT),避免信号嵌套导致逻辑混乱。
默认行为与忽略
注册 SIG_IGN 可忽略信号(如 signal(SIGPIPE, SIG_IGN) 忽略管道破裂信号)。
注册 SIG_DFL 可恢复默认行为(如 signal(SIGINT, SIG_DFL) 恢复 Ctrl+C 终止程序的默认行为)。
四、完整示例:处理自定义信号 SIGUSR1
c
运行
#include
#include
#include
#include
 
// 处理SIGUSR1信号(用户自定义信号1)
void sigusr1_handler(int signum) {
    printf("收到自定义信号 %d(SIGUSR1)\n", signum);
}
 
int main() {
    printf("进程PID:%d,发送信号:kill -USR1 %d\n", getpid(), getpid());
 
    // 用sigaction注册SIGUSR1
    struct sigaction act;
    act.sa_handler = sigusr1_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (sigaction(SIGUSR1, &act, NULL) == -1) {
        perror("sigaction失败");
        exit(1);
    }
 
    // 等待信号
    while (1) {
        sleep(1);
    }
    return 0;
}
 
测试方法:
 
编译运行程序,获取 PID(如输出 进程PID:1234)。
另开终端发送信号:kill -USR1 1234,程序会打印信号处理信息。
总结
信号处理函数必须遵循 void (*)(int) 原型。
注册函数优先使用 sigaction()(功能全面、行为标准),简单场景可用 signal()。
处理函数内避免调用非异步安全函数,注意可重入性和信号阻塞逻辑。
 
通过这种方式,进程可灵活自定义对信号的响应,实现如优雅退出、日志轮转、状态更新等功能。

三二互联专业提供香港VPS,美国VPS主机,香港云服务器租用等业务香港美国到大陆CN2 GIA速度最快

上一篇:没有了 下一篇:进程支持信号或IPC的条件是什么?

美国GIA服务器三二互联版权所有 WWW.250.cc 2008-2015 All Rights Reserved
三二互联 - 专业的美国C3服务器香港vps、抗DOOS流量清洗、云备份系统、网站加速系统、美国GIA服务器和香港云服务器产品提供商
三二互联24小时在线工单系统为您提供全面、专业、周到的技术支持与服务
咨询热线:400-679-9994(免长话费)