在 C 中等待中断的有效方法
Efficient way to wait for an interrupt in C
我在 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(;;)
会占用资源。我想知道该做什么或关于该做什么的指示(线程等)。
我不确定 WiringPi 特别是什么,但是使用 pthread_cond_t
在完成任务后等待 signal
由您的中断处理程序引导怎么样?
This为参考。
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
标志编译和 link 您的代码。
我最近不得不这样做。我的理论是 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 使用的。
这取决于您是否需要在用户级别通知。有一些情况的话:
1) 'I need no notification at all since I do everythng in interrupt state'。好的,在 main() 中等待使用长 Sleep() 循环,或 Sleep(INFINITE)(如果可用),或等待某个从未发出信号的同步对象,或循环一些 'set low power state' 或 'HALT' 指令.这消除了从用户状态执行的需要,只让您的处理器等待中断。
2)“我需要用户状态下的通知,但我不关心延迟”。好的,从中断状态设置一些原子 int 或布尔值,并从需要注意中断可能发生的任何 main() 或线程轮询它。这样的轮询可能会很浪费并且响应缓慢,但是如果您不需要关心您的应用程序,那很好:)
3) 'I need notification in user state as fast as is praticable'。 'classic' 实现这种信号的方式是让处理程序线程在信号量上等待,从 interrupt-handler 和 'instruct' 发出信号量,OS 它必须执行重新调度interrupt-handler 一结束。所以使等待线程 ready/running。其他信号机制,例如。 events/condvars,从 interrupt-state 发信号也可能是安全的,但你应该检查你的 OS 文档。
我不能做什么?您不能,和/或不得在中断状态下调用任何可能试图阻止的东西。那是灾难性的,你的 OS 可能会摔倒:(
您也可以使用 semaphore. sem_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()
的潜在虚假唤醒。
我会(和 do,在编码嵌入时)宁愿使用自旋锁 while(1) ;
。它直截了当并表达了意图——永远不要超过这一点。
睡眠不仅有过期时间,这可能不是马上的问题,但多年后就会成为问题。它还必须执行一些计算才能实际计算时间。
这是 sleep(0xFFFFFFFF);
在 Intel Core i3-4330TE 上的比较:
.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 [=10=], %eax
call sleep
movl [=10=], %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 到达之前识别此模式。
话虽如此,"keep the program running, using minimal resources" 的正确方法是查看处理器提供的 the sleep modes (page 2-14 or 36)。
我在 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(;;)
会占用资源。我想知道该做什么或关于该做什么的指示(线程等)。
我不确定 WiringPi 特别是什么,但是使用 pthread_cond_t
在完成任务后等待 signal
由您的中断处理程序引导怎么样?
This为参考。
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
标志编译和 link 您的代码。
我最近不得不这样做。我的理论是 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 使用的。
这取决于您是否需要在用户级别通知。有一些情况的话:
1) 'I need no notification at all since I do everythng in interrupt state'。好的,在 main() 中等待使用长 Sleep() 循环,或 Sleep(INFINITE)(如果可用),或等待某个从未发出信号的同步对象,或循环一些 'set low power state' 或 'HALT' 指令.这消除了从用户状态执行的需要,只让您的处理器等待中断。
2)“我需要用户状态下的通知,但我不关心延迟”。好的,从中断状态设置一些原子 int 或布尔值,并从需要注意中断可能发生的任何 main() 或线程轮询它。这样的轮询可能会很浪费并且响应缓慢,但是如果您不需要关心您的应用程序,那很好:)
3) 'I need notification in user state as fast as is praticable'。 'classic' 实现这种信号的方式是让处理程序线程在信号量上等待,从 interrupt-handler 和 'instruct' 发出信号量,OS 它必须执行重新调度interrupt-handler 一结束。所以使等待线程 ready/running。其他信号机制,例如。 events/condvars,从 interrupt-state 发信号也可能是安全的,但你应该检查你的 OS 文档。
我不能做什么?您不能,和/或不得在中断状态下调用任何可能试图阻止的东西。那是灾难性的,你的 OS 可能会摔倒:(
您也可以使用 semaphore. sem_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()
的潜在虚假唤醒。
我会(和 do,在编码嵌入时)宁愿使用自旋锁 while(1) ;
。它直截了当并表达了意图——永远不要超过这一点。
睡眠不仅有过期时间,这可能不是马上的问题,但多年后就会成为问题。它还必须执行一些计算才能实际计算时间。
这是 sleep(0xFFFFFFFF);
在 Intel Core i3-4330TE 上的比较:
.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 [=10=], %eax
call sleep
movl [=10=], %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 到达之前识别此模式。
话虽如此,"keep the program running, using minimal resources" 的正确方法是查看处理器提供的 the sleep modes (page 2-14 or 36)。