我在树莓派上使用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(;;)
会占用资源。我想知道该做什么或指示做什么(线程等)。
答案 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)
您还可以使用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()
的潜在虚假唤醒错误。
答案 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)。