signal()信号测试

测试代码1:

# include <stdio.h>
# include <error.h>
# include <sys/types.h>
# include <string.h>
# include <signal.h>
typedef void Sigfunc(int);
void sig_usr(int signo){
	if(signo == SIGUSR1) printf("SIGUSR1 received.\n");
	else if(signo == SIGUSR2) printf("SIGUSR2 received.\n");
	//else if(signo == SIGTERM) printf("SIGTERM received.\n");
	else return;
	
}
int main(int argc, char *argv[]){
	if(signal(SIGUSR1, sig_usr) == SIG_ERR) perror("cant catch sigusr1");
	if(signal(SIGUSR2, sig_usr) == SIG_ERR) perror("cant catch sigusr2");
	//if(signal(SIGTERM, sig_usr) == SIG_ERR) perror("cant catch sigterm");
	for(;;) pause();
	return 0;
}

 

$ gcc unix.c -o unix

./unix &
[1] 4339

$ kill -SIGUSR1 4339
SIGUSR1 received.

$ kill -SIGUSR2 4339
SIGUSR2 received.

$ kill 4339

$
[1]+  已终止               ./unix

 sig_usr处理用户定义的信号SIGUSR1和SIGUSR2,kill指令向进程发送信号,由于进程没有处理终止信号,所以收到终止信号SIGTERM时程序默认被终止(代码注释部分就是处理终止信号的)。

 

测试代码2:进行信号处理函数时能否捕捉其他信号?

# include <stdio.h>
# include <error.h>
# include <errno.h>
# include <sys/types.h>
# include <string.h>
# include <signal.h>
typedef void Sigfunc(int);
void handler(){
	printf("begin SIGINT\n");
	for(int i=0; i<2000000000; ++i);
	printf("end SIGINT\n");
}
void handler2(){
	printf("begin SIGUSR1\n");
	printf("end SIGUSR1\n");
}
int main(int argc, char *argv[]){
	signal(SIGINT, handler);
	signal(SIGUSR1, handler2);
	pause();
	perror("done ");
	return 0;
}

$ ./unix &
[1] 3548
$ kill -SIGINT 3548
begin SIGINT
$ kill -SIGUSR1 3548
begin SIGUSR1
end SIGUSR1
$ end SIGINT
done : Interrupted system call

 结果显示为可以(另外经过测试在执行信号A的处理函数时是会阻塞信号A的到来的)。

测试代码3:sigaction函数代替signal函数

# include <stdio.h>
# include <error.h>
# include <errno.h>
# include <sys/types.h>
# include <string.h>
# include <signal.h>
typedef void Sigfunc(int);
void handler(){
	printf("handling singo.\n");
}
Sigfunc *signal(int signo, Sigfunc *func){
	struct sigaction act, oact;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	act.sa_handler = func;
	if(signo == SIGALRM) act.sa_flags |= SA_INTERRUPT;
	else act.sa_flags |= SA_RESTART;
	if(sigaction(signo, &act, &oact) < 0) return SIG_ERR;
	return oact.sa_handler;
}
int main(int argc, char *argv[]){
	signal(SIGINT, handler);
	signal(SIGALRM, handler);
	alarm(8);
	char s[10]={0};
	read(0, s, sizeof(s));
	printf("%s\n",s);
	perror("done");
	return 0;
}

$ ./unix
^Chandling singo.
^Chandling singo.
^Chandling singo.
^Chandling singo.
handling singo.


done: Interrupted system call

 

 sigaction比signal提供了更多功能,包括阻塞信号sa_mask和状态位sa_flags,后者可以设置被信号中断的函数是否自动重启(比如低速系统调用read、write)。上面代码如果是alarm引起的中断不重启,其他重启,也就是8秒内read要返回,否则就跳过了。另外老版的signal函数只能生效一次,而sigaction函数能永久生效。

### 信号(signal)在C语言中的使用方法 在操作系统中,**信号signal)** 是一种进程间通信的方式,用于通知某个进程发生了某种事件。例如,用户按下 `Ctrl+C` 可以发送一个中断信号给正在运行的程序。通过 `signal.h` 头文件提供的函数,可以在C语言中实现对信号的捕获和处理。 #### 基本信号处理机制 在C语言中,可以使用 `signal()` 函数注册信号处理函数。以下是一个简单的示例,演示如何捕获并处理 `SIGINT` 和 `SIGUSR1` 信号: ```c #include <stdio.h> #include <signal.h> #include <unistd.h> // 定义信号处理函数 void sigint_handler(int signum) { printf("Caught SIGINT (Interrupt signal)\n"); } void sigusr1_handler(int signum) { printf("Caught SIGUSR1 (User-defined signal 1)\n"); } int main() { // 注册信号处理函数 signal(SIGINT, sigint_handler); signal(SIGUSR1, sigusr1_handler); printf("Waiting for signals...\n"); // 程序持续运行等待信号触发 while (1) { sleep(1); // 避免CPU空转 } return 0; } ``` 此代码会持续等待信号的到来,并在收到 `SIGINT` 或 `SIGUSR1` 时调用相应的处理函数。例如,可以通过在终端按 `Ctrl+C` 来发送 `SIGINT` 信号。 #### 信号处理函数中是否能捕捉其他信号? 当一个信号处理函数被调用时,默认情况下系统不会阻塞其他信号的传递,这意味着在执行当前信号处理函数的过程中可能会接收到另一个信号[^2]。为了测试这一点,可以编写如下代码: ```c #include <stdio.h> #include <signal.h> #include <unistd.h> #include <errno.h> void sigint_handler(int signum) { printf("Handling SIGINT\n"); for(volatile long i = 0; i < 2000000000L; ++i); // 模拟长时间操作 printf("Finished handling SIGINT\n"); } void sigusr1_handler(int signum) { printf("Handling SIGUSR1\n"); } int main() { signal(SIGINT, sigint_handler); signal(SIGUSR1, sigusr1_handler); printf("PID: %d\n", getpid()); printf("Send SIGINT or SIGUSR1 to test\n"); while (1) { pause(); // 等待信号 } return 0; } ``` 运行该程序后,在第一个信号处理函数执行期间发送第二个信号,观察其行为。如果希望在处理一个信号时屏蔽其他信号,应使用更高级的信号管理接口如 `sigaction()` 并设置适当的掩码。 #### 不可靠信号与可靠性问题 早期版本的 `signal()` 接口存在一些局限性,包括无法查询当前信号处理方式而不改变它的问题,以及所谓的“不可靠信号”行为:即某些系统上信号处理可能不会自动重启被中断的系统调用[^3]。为了解决这些问题,现代系统推荐使用 `sigaction()` 函数来替代 `signal()`,因为 `sigaction()` 提供了更多控制选项并且行为更加一致。 以下是使用 `sigaction()` 的等效示例: ```c #include <stdio.h> #include <signal.h> #include <unistd.h> void handler(int signum) { printf("Received signal %d\n", signum); } int main() { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; // 设置SIGINT的处理动作 if (sigaction(SIGINT, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("Waiting for signals...\n"); while (1) { sleep(1); } return 0; } ``` 这段代码展示了如何使用 `sigaction()` 更加精确地控制信号的行为。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值