Linux进程6-alarm闹钟定时终止、raise发送信号、abort终止、pause挂起进程验证

目录

1.alarm函数

1.1关键点

1.2单个alarm函数定时

1.3两个alarm函数定时

2.raise函数

2.1核心行为‌

2.2 raise与 kill 的区别

2.3程序:

3.abort函数

4.pause 函数

4.1 pause简单挂起

4.2父进程挂起,子进程发信号


1.alarm函数

函数原型:

#include <unistd.h>
 unsigned int alarm(unsigned int seconds);

 功能:定时器,闹钟,当设定的时间到达时,会产生SIGALRM信号

 参数:
 seconds:设定的秒数

 返回值:
 如果alarm函数之前没有alarm设置,则返回0
 如果有,则返回上一个alarm剩余的时间

1.1关键点

  1. 信号行为

    • SIGALRM默认终止进程,但可通过信号处理函数自定义行为。
    • 使用signalsigaction注册处理函数。推荐sigaction以确保可移植性。
  2. 覆盖机制

    • 多次调用alarm会覆盖之前的定时器,返回前一个定时器的剩余时间。
    • 调用alarm(0)取消定时器,返回剩余时间。
  3. 精度与限制

    • 精度为秒级。更高精度需用setitimertimer_create
    • sleep等函数可能冲突(因内部使用相同信号),建议改用nanosleep避免干扰。
  4. 多线程与进程

    • 定时器是进程级别的,多线程中需注意线程安全。
    • fork后子进程不继承定时器;exec会取消定时器。

 应用场景

  • 超时控制:如阻塞I/O操作设置超时,防止无限等待。
  • 任务调度:定时执行特定任务(需结合信号处理)。

1.2单个alarm函数定时

程序:

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

int main(int argc, char *argv[])
{
    unsigned int i;
    unsigned int sec;
    //当执行到alarm之后,代码会接着往下执行,当设定的时间到后,
    //会产生SIGALRM终止信号

    sec = alarm(5);
    printf("alarm返回值 = %d\n", sec);

    while(1)
    {
    	   i++;
        printf("程序运行 第 %d 次\n",i);
        sleep(1);
    }
	
	return 0;
}

运行结果:alarm设置5秒的闹钟,程序运行5秒后,产生SIGALRM终止信号执行结束。

1.3两个alarm函数定时

程序:

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

int main(int argc, char *argv[])
{
    unsigned int i;
    unsigned int sec;
    //当执行到alarm之后,代码会接着往下执行,当设定的时间到后,
    //会产生SIGALRM终止信号

    //如果alarm之前没有设置其他闹钟,则返回0,如果之前设置了,则返回之前剩余的秒数
    //如果一个程序中出现多个alarm闹钟,第一个如果没有到达指定的时间就遇到第二个
    //则第一个的闹钟时间清除,按照第二个alarm闹钟的时间继续向下运行

    sec = alarm(5);
    printf("alarm返回值 = %d\n", sec);

    sleep(2);//阻塞2秒

    sec = alarm(8);
    //返回上一个闹钟剩余时间
    printf("当前alarm 前面有alarm函数 返回值 = %d\n", sec);

    while(1)
    {
    	   i++;
        printf("程序运行 第 %d 次\n",i);
        sleep(1);
    }
	
	return 0;
}

运行结果:

如果一个程序中出现多个alarm闹钟,第一个如果没有到达指定的时间就遇到第二个则第一个的闹钟时间清除,按照第二个alarm闹钟的时间继续向下运行。

程序中第一个闹钟先设置5秒,睡眠阻塞2秒,闹钟时间还剩余3秒,接着又遇见第二个闹钟设置8秒,第一个闹钟时间清零,闹钟时间按第二个闹钟运行。

2.raise函数

函数原型:

#include <signal.h>
int raise(int signum);

功能:
给调用进程本身发送一个信号。

参数:
signum:要发送的信号编号(如 SIGINT、SIGTERM 等)

返回值:
成功返回 0,失败返回非0。

2.1核心行为

  1. ‌向自身进程发送信号‌
    raise(sig) 等价于 kill(getpid(), sig),但 raise 是标准 C 库函数,可移植性更强。

  2. ‌触发信号处理逻辑‌
    若已通过 signal() 或 sigaction() 注册了信号处理函数,调用 raise 会执行对应的处理逻辑。

  3. ‌默认行为‌
    若未捕获信号,执行信号的默认动作(如 SIGTERM 会终止进程)。

2.2 raise与 kill 的区别

raise(sig) 等价 kill(getpid(), sig)

  • raise 是进程内操作的简化版本,无需指定进程ID。
  • raise 是标准 C 库函数,可移植性更强。
特性raisekill
目标进程仅当前进程 (getpid())可指定任意进程或进程组
信号来源进程内部主动触发通常由外部进程发送
可移植性标准 C 库函数,跨平台兼容POSIX 系统调用

2.3程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char const *argv[])
{
    int num = 0;

    while(1)
    {      
        sleep(1);
        num++;
        printf("程序运行 第 %d 次\n",num);

        //当循环执行5秒后,进程退出
        if(num == 5)
        {
            //使用raise给当前进程本身发送信号
            raise(SIGTERM); //默认终止信号
          //  raise(SIGALRM); //闹钟终止
          //  raise(SIGINT); //终止,终端按下 Ctrl+C
            //kill(getpid(), SIGALRM);
        }
    }

    return 0;
}

运行结果:

3.abort函数

函数原型:

#include <stdlib.h>
void abort(void);

功能:
向进程发送一个 SIGABRT 信号,默认情况下进程会退出。
默认行为是终止进程并生成核心转储文件(core dump)

注意:即使 SIGABRT 信号被加入阻塞集,一旦进程调用了 abort 函数,
进程也还是会被终止,且在终止前会刷新缓冲区,关文件描述符。

程序:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char const *argv[])
{
    int num = 0;

    while(1)
    {
        sleep(1);
        num++;
         printf("程序运行 第 %d 次\n",num);

        //当循环执行5秒后,进程退出
        if(num == 5)
        {
            abort();//终止运行
        }
    }

    return 0;
}

运行结果:

4.pause 函数

函数原型:

#include <unistd.h>
int pause(void);

功能:
将调用进程挂起直至捕捉到信号为止。这个函数通常用于判断信号是否已到。

返回值:
直到捕获到信号,pause 函数才返回-1,且 errno 被设置成 EINTR。

4.1 pause简单挂起

(1)pause简单挂起返回值测试

程序:

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

void alarm_handler(int sig) 
{
    printf("定时器触发 SIGALRM 信号(%d)\n", sig);
}

int main()
{
    signal(SIGALRM, alarm_handler);
    alarm(3);  // 设置 3 秒定时
    
    int ret = pause();  // 等待定时器信号
    if (ret == -1) 
    {
        if (errno == EINTR) 
        {
            printf("pause 被 SIGALRM 中断\n");
        } 
        else
        {
            perror("pause 错误");
        }
    }
    return 0;
}

运行结果:

(2)pause简单挂起,阻值while(1)运行

程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
      int num = 0;
       alarm(3);//设置3秒定时闹钟,3秒后,产生SIGALRM终止信号执行结束

    while(1)
    {      
        sleep(1);
        num++;
        printf("程序运行 第 %d 次\n",num);
        
      pause();  // 进程挂起,等待信号
    }

	return 0;
}

运行结果:程序正常运行while(1)应每过一秒打印一次,加入pause进程挂起,等待信号,直到闹钟定时3秒后,发送终止信号,程序运行结束。

4.2父进程挂起,子进程发信号

程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>

int main(int argc, char *argv[])
{
    pid_t pid;
    int num = 0;
    pid = fork();
    if(pid < 0)
    {
        perror("fail to fork");//创建失败
        exit(1);//退出
    }
    else if(pid > 0) //父进程的代码区
    {
        printf("父进程运行... \n");

        //使用pause阻塞等待捕捉信号
        pause();// 进程挂起,等待信号
    }
    else //子进程的代码区 
    {
        printf("子进程运行... \n");
		while(1)
		{
			sleep(1);//阻塞1秒
			num++;
			printf("子进程运行 第 %d 次 \n", num);

			if(num == 3)
			{
				printf("给父进程发送终止信号 \n");
				//给父进程发送终止信号	
        			kill(getppid(), SIGTERM);

        			exit(1);//退出
			}
		}
        

	   
    }

	return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值