在C中等待中断的有效方法

时间:2016-01-22 11:35:55

标签: c embedded raspberry-pi

我在树莓派上使用WiringPi。有了它我分配了一个稍后调用的中断函数。我不确定在等待中断被呼叫时该怎么做。

示例使用(自旋锁?)for (;;),例如

int main()
{
    // register interrupt
    wiringPiISR( 18, INT_EDGE_BOTH, &myInterrupt );

    for (;;) {
        // really?
    }
    return 0;
}

我注意到sleep也有效。无论睡眠如何都会调用中断

int main() 
{
    // register interrupt
    wiringPiISR( 18, INT_EDGE_BOTH, &myInterrupt );

    for (;;) {
        sleep(1000000);
    }
    return 0;
}

使用最少的资源保持程序运行的最佳做法是什么(比如这是否适用于背景恶魔)?

来自其他语言,我原以为for(;;)会占用资源。我想知道该做什么或指示做什么(线程等)。

6 个答案:

答案 0 :(得分:3)

WiringPi设置一个单独的线程并从该线程调用你的isr函数。

然后,您可以使用pthread条件变量来阻止另一个线程main(),并在发生中断时让isr函数将其唤醒。

#include <pthread.h>

pthread_cond_t isr_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t isr_mtx = PTHREAD_MUTEX_INITIALIZER;
unsigned int isr_count = 0;

void myInterrupt(void)
{
    pthread_mutex_lock(&isr_mtx);
    isr_count++;
    pthread_cond_signal(&isr_cond);    
    pthread_mutex_unlock(&isr_mtx);

}

int main() 
{
    // register interrupt
    wiringPiISR( 18, INT_EDGE_BOTH, &myInterrupt );

    for (;;) {
       pthread_mutex_lock(&isr_mtx);
       while (isr_count == 0) {
          pthread_cond_wait(&isr_cond, &isr_mtx);
       }
       //add logic here to handle the ISR, isr_count
       //tells you how many ISRs occured.
       //heavy work should be moved outside the mutex.

      isr_count = 0;
      pthread_mutex_unlock(&isr_mtx);
    }

    return 0;
}

您需要使用-pthread标记编译和链接您的代码。

答案 1 :(得分:3)

我最近不得不这样做。我的理论是KISS。根据定义编写sleep以使用最少的资源 - 使用它意味着我不必关心线程。

原始Raspberry Pi B上的简单,可读且没有可衡量的性能:

int main() 
{
    // register interrupt
    wiringPiISR( 18, INT_EDGE_BOTH, &myInterrupt );

    for (;;) {
        sleep(UINT_MAX);
    }
    return 0;
}

注意使用UINT_MAX来最小化for循环调用的数量 - 这假设是无符号的32位定时器延迟,这是WiringPi使用的。

答案 2 :(得分:2)

这取决于您是否需要在用户级别进行通知。在某些情况下,然后:

1)&#39;我完全不需要通知,因为我每次都处于中断状态&#39;。很好,等待在main()中使用长Sleep()循环,或Sleep(INFINITE)(如果可用),或等待一些从未发出信号的同步对象,或循环一些设置低功耗状态&#39;或者&#39; HALT&#39;指令。这将从用户状态中删除执行需要,并让处理器等待中断。

2)&#39;我需要在用户状态下发送通知,但我并不关心延迟问题。好的,从中断状态设置一些原子int或布尔值,并从需要注意中断可能发生的main()或线程中调查它。这样的民意调查可能会浪费并且反应缓慢,但如果你不需要在你的应用程序中小心,那么很好:)

3)&#39;我需要在用户状态下尽可能快地通知&#39;。经典&#39;实现这种信令的方式是让一个处理程序线程在信号量上等待,从中断处理程序发出信号,并指示&#39;指示&#39;一旦中断处理程序结束,它必须执行重新安排的操作系统。所以使等待线程准备好/正在运行。其他信号机制,例如。事件/ condvars,也可以安全地从中断状态发出信号,但是你应该查看你的操作系统文档。

我不能做什么?你不能和/或不能在可能试图阻止的中断状态下调用任何东西。这是灾难性的,你的操作系统可能会很难挫败:(

答案 3 :(得分:2)

您还可以使用semaphoresem_post() must be async-signal-safe

#include <semaphore.h>

static sem_t staticSem;

void myInterupt( void )
{
    sem_post( &staticSem );
}

int main() 
{
    sem_init( &staticSem, 0, 0 );

    // register interrupt
    wiringPiISR( 18, INT_EDGE_BOTH, &myInterrupt );

    for (;;) {
        sem_wait( &staticSem );
        ...
    }
    return 0;
}

错误检查和处理来自sem_wait()的潜在虚假唤醒错误。

答案 4 :(得分:0)

我特别不确定WiringPi,但是在完成任务时使用等待pthread_cond_t等待signal的中断处理程序如何?

This是一个参考。

答案 5 :(得分:0)

我愿意(和do,在嵌入编码时)而不是使用自旋锁while(1) ;。它很简单,表达意图 - 永远不会超越这一点。

睡眠不仅有一个到期时间,这可能不会立即成为问题,但在多年后成为一个问题。它还必须执行一些计算以实际计算时间。

以下是英特尔酷睿i3-4330TE上的sleep(0xFFFFFFFF);之间的比较:

        .file   "test.c"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $-1, %edi
        movl    $0, %eax
        call    sleep
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Debian 4.9.2-10) 4.9.2"
        .section        .note.GNU-stack,"",@progbits

while(1);方法:

        .file   "test.c"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
.L2:
        jmp     .L2
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Debian 4.9.2-10) 4.9.2"
        .section        .note.GNU-stack,"",@progbits

如果没有时间跟踪,那么工作就会减少。我不确定linux调度程序是否可以在ISR到达之前识别此模式。

说完这个,正确的方法是“保持程序运行,使用最少的资源&#34;是研究处理器提供的the sleep modes (page 2-14 or 36)