【问题标题】:POSIX timers and POSIX signals handlingPOSIX 计时器和 POSIX 信号处理
【发布时间】:2012-02-18 23:14:51
【问题描述】:

我正在开发一个简单的软件来检查我是否能够使用我研究过的关于 POSIX 计时器和信号的知识进行编程。

我正在尝试做一个简单的程序,它启动一个计时器并在一定的纳秒内发出一个信号

下面的程序运行不好,所以我写了一些关于我的代码的cmets,这样你就可以检查我是否正确地学习了。 您可以在页面底部找到完整的代码清单。

各种印花,如

prinf("1\n")
用于检查程序过早退出的位置。 我将
struct sigevent sigeventStruct
作为计时器生成的到期事件的结构。 第一个参数设置为 SIGEV_SIGNAL 所以这是它将发出的信号类型。 /// 您可以在代码清单中阅读的各种 memset 是零初始化结构。
if(timer_create(_POSIX_MONOTONIC_CLOCK, &sigeventStruct, &timer1) == -1)

是创建一个 POSIX 计时器。 POSIX MONOTONIC CLOCK 是一种计时器,&sigeventStruct 是指向结构的指针,该结构描述了它是如何由计时器到期生成的事件。 &timer1 是指向特定计时器名称的指针。

if(timer_settime(timer1, NULL, &tempoIniziale, &tempoFinale) == -1)

通过此过程,计时器已启用,因此您可以使其生成到期时间。 timer1 是计时器的名称,0 是标志。 GAPIL 书说: &tempoIniziale 和 &tempoFinale 是指向 itimerspec 结构的指针。我不太明白&old_timer是什么意思。在 GAIL 书中,您可以阅读:

struct sigaction, oldSigAzione

将作为参数传递给 sigaction POSIX 信号处理程序的 sigaction 结构

sigaction (SIGEV_SIGNAL, NULL, &oldSigAzione)

SIGEV_SIGNAL 是它必须处理的信号类型,NULL 是可以放置指向 const struct sigaction 的指针的位置,&oldSigAzione 是指向我之前提到的 sigaction struct 的指针。在这里我又没有理解这两个指向 sigaction struct 的指针之间的区别。

我的问题是: 为什么程序在打印 printf("19\n") 的数字 19 之前退出;以及为什么不执行 printf("Timer scaduto\n");函数内部无效终止处理程序(int signum)?

这是我的代码:

#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/fcntl.h>
#include <sys/wait.h>
#include <stdbool.h>

void termination_handler(int signum)
{
    printf("Timer scaduto\n");
}

int main()
{
    printf("Start\n");
    printf("1\n");
    struct sigevent sigeventStruct; // sigevent struct that will be used by timer1 timer
    printf("2\n");
    memset(&sigeventStruct, 0, sizeof sigeventStruct); // zero initialize struct
    printf("3\n");
    sigeventStruct.sigev_notify = SIGEV_SIGNAL; // kind of notification of timer1 expiration
    printf("4\n");
    sigeventStruct.sigev_signo = 10;
    printf("5\n");

    timer_t timer1; // create a timer identifier
    printf("6\n");
    if(timer_create(_POSIX_MONOTONIC_CLOCK, &sigeventStruct, &timer1) == -1)
    {
        printf( "Errore timer_create: %s\n", strerror( errno ) );
    }

    printf("7\n");
    struct itimerspec tempoIniziale;
    printf("8\n");
    memset(&tempoIniziale, NULL, sizeof tempoIniziale); // zero initialize struct
    printf("9\n");
    tempoIniziale.it_value.tv_nsec = 100000000;
    //tempoIniziale.it_interval.tv_nsec = 10000;
    printf("10\n");


    if(timer_settime(timer1, 0, &tempoIniziale, NULL) == -1) // timer armed
    {
        printf( "Errore timer_settime: %s\n", strerror( errno ) );
    }
    printf("11\n");
    for(int i = 0; i< 10; i++)
    {
        printf("ciclo %d\n", i);
    }

    struct sigaction oldSigAzione;
    printf("12\n");
    memset(&oldSigAzione, 0, sizeof oldSigAzione);
    printf("13\n");
    oldSigAzione.sa_handler = termination_handler;
    printf("14\n");
    sigemptyset (&oldSigAzione.sa_mask);

    printf("15\n");
    oldSigAzione.sa_flags = 0;

    printf("16\n");
    sigaction (SIGEV_SIGNAL, NULL, &oldSigAzione);
    printf("17\n");
    if(oldSigAzione.sa_handler == SIG_IGN)
    {
        printf("Segnale ignorato\n");
    }
    printf("18\n");
    for(int i = 0; i < 1000000000000; i++)
    {

    }
    printf("19\n");
    printf("number of expirations %d\n", timer_getoverrun(timer1));
    return 0;
}

【问题讨论】:

  • 空的 for 循环不是延迟的方法。现代编译器将其编译为根本没有代码。试试sleep...
  • 另外,printf 不是异步信号安全的。除非您在代码中避免所有可能被信号中断的异步信号不安全函数调用,否则您不能从信号处理程序中使用它。

标签: c timer posix signals


【解决方案1】:

在对timer_create() 的调用中,第一个参数应该是一个时钟ID,例如CLOCK_MONOTONIC_POSIX_MONOTONIC_CLOCK 只是一个宏,你可以在编译时用来测试系统是否支持CLOCK_MONOTONIC

sigaction() 的第一个参数应该是信号号,而不是 SIGEV_SIGNAL。在您的情况下,您使用的是信号 10,但这不是一个好的选择,因为通常这将是预定义的操作系统信号之一。通常,您会使用SIGUSR1 之类的用户定义信号或SIGRTMIN 之类的实时信号,因为它们是为应用程序定义的。此外,您对sigaction() 的调用不会设置信号处理程序,因为第二个参数是NULL。第二个参数应该是指向您的新信号操作的指针。相反,您使用的是用于返回前一个信号动作的第三个参数。这允许您临时设置新的信号操作,同时保存旧的信号操作,然后当您完成新操作后,您可以将其设置回保存的值。由于您再也不会更改它,因此您无需获取旧值。同样为了稳健,应该在启动计时器之前设置信号操作,因为您的程序的执行可能会延迟(例如,如果系统真的陷入困境)并且计时器可能会在您到达代码中设置的点之前到期信号处理程序。

正如 R 所提到的,printf() 不是异步信号安全的,因此不应从您的信号处理程序中调用它。

【讨论】:

  • 非常感谢,您的帮助很宝贵
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-04
  • 2023-03-10
  • 1970-01-01
相关资源
最近更新 更多