使用sigtimedwait()

时间:2017-10-24 16:20:14

标签: linux signals

我不是编程新手,但对Linux来说还不是新手。我正在尝试使用信号异步捕获按钮,如下所示:

  1. 运行一个工作线程,当按下按钮时,该线程会引发SIGUSR1。
  2. 围绕sigtimedwait()运行一个循环(主线程),它将每两秒旋转一次信息(只要没有按下按钮)或中断(按下按钮时)。
  3. 根据notes on sigtimedwait(),应该阻止你想要等待的信号,然后调用sigtimedwait()。但是我从来没有看到sigtimedwait()捕捉被阻挡的信号。我已经通过几种方式运行下面的代码来查看不同场景会发生什么:

    • 禁用pthread_sigmask()调用,调用signal()禁用, 结果:程序退出并显示消息“用户定义的信号1”。
    • 禁用pthread_sigmask()调用,调用signal(),结果: 消息“按钮1按下sync1命中”出现,sigtimedwait()始终显示 返回EAGAIN。
    • 调用pthread_sigmask()启用,调用signal()禁用,结果: 消息“按下按钮1”出现,sigtimedwait()始终返回 EAGAIN。
    • 调用pthread_sigmask()启用,调用signal()启用,结果 当然与之前相同,因为不会调用处理程序。

    所有这些都是预期的,除了sigtimedwait()似乎没有抓住信号的事实。

    我查看了类似的代码,例如this。但是我不明白特定代码是如何工作的:SIGUSR1没有被阻止,所以提高它应该立即终止程序(SIGUSR1的默认动作)。

    看起来我在这里遗漏了一些东西。我究竟做错了什么?或者在工作线程中使用raise()的错误是什么?我正在使用Raspbian Stretch(Debian 9.1)在Raspberry Pi 3上运行它,可能会出现问题吗?

    [我知道printf()不应该在信号处理程序中使用,但为了这个目的它可以工作]

    任何帮助表示感谢,谢谢!

    #include <stdio.h>
    #include <stdlib.h>
    #include <bcm2835.h>
    #include <signal.h>
    #include <pthread.h>
    #include <errno.h>
    
    #define PIN_BUTTON1 RPI_V2_GPIO_P1_22   // GPIO #24
    
    // Thread function
    void* check_button1(void* param)
    {
        while (true)
        {
            if (bcm2835_gpio_lev(PIN_BUTTON1) == HIGH)
            {
            printf("Button 1 pressed ");
            raise(SIGUSR1);
            }
            delay(250);
        }
    }
    
    // Signal handler, if applied
    volatile sig_atomic_t usr_interrupt = 0;
    void sync1(int sig)
    {
        printf("sync1 hit ... ");
        usr_interrupt = 1;
    }
    
    int main(int argc, char** argv)
    {
        if (!bcm2835_init())
        {
            printf("Failed to initialize BCM2835 GPIO library.");
            return 1;
        }
        bcm2835_gpio_fsel(PIN_BUTTON1, BCM2835_GPIO_FSEL_INPT);
    
        sigset_t sigusr;
        sigemptyset(&sigusr);
        sigaddset(&sigusr, SIGUSR1);
        pthread_sigmask(SIG_BLOCK, &sigusr, NULL);
        signal(SIGUSR1, sync1);
    
        // Start the threads to read the button pin state
        pthread_t th1;
        pthread_create(&th1, NULL, check_button1, NULL);
    
        // Create a two second loop
        struct timespec timeout = { 0 };
        timeout.tv_sec = 2;
        usr_interrupt = 0;
        int nLoopCount = 0;
        while (true)
        {
            printf("Loop %d, waiting %d seconds ... ", ++nLoopCount, timeout.tv_sec);
            int nResult = sigtimedwait(&sigusr, NULL, &timeout);
            if (nResult < 0)
            {
            switch (errno)
            {
                case EAGAIN:    printf("EAGAIN ");   break;   // Time out, no signal raised, next loop
                case EINTR: printf("EINTR ");    break;   // Interrupted by a signal other than SIGCHLD.
                case EINVAL:    printf("EINVAL ");   exit(1); // Invalid timeout
                default:    printf("Result=%d Error=%d ", nResult, errno);   break;
            }
            printf("\n");
            continue;
            }
            printf("Signal %d caught\n", nResult);
        }
    
        return 0;
    }
    

    ADDENDUM:与此同时,我通过 kill(getpid(),SIGUSR1)替换 raise(SIGUSR1)来实现此目的。很奇怪,因为according to the manual raise(x)相当于单线程程序中的 kill(getpid,x) pthread_kill(pthread_self() ,x)在多线程的。用 pthread_kill(pthread_self,SIGUSR1)替换 raise(SIGUSR1) 无效。如果有人能向我解释这个......

0 个答案:

没有答案