Python C扩展,用于睡眠功能
问题描述:
我正在为GPIO驱动程序提供的功能编写Python extension。我在set_bit()和clear_bit()这样的简单函数上轻松取得了进展。但是现在我需要实现wait_int(),这个睡眠直到在输入引脚上检测到一个事件,我不确定在c和python之间编排这条命令的正确方法。下面是在c。使用功能的精简例子:Python C扩展,用于睡眠功能
main(int argc, char *argv[])
{
int c;
//some setup like testing port availability, clearing interrupts, etc
...
while(1)
{
printf("**\n");
c = wait_int(1);//sleeps until an interrupt occurs on chip 1
if(c > 0) {
printf("Event sense occured on Chip 1 bit %d\n",c);
++event_count;
}
else
break;
}
printf("Event count = %05d\r",event_count);
printf("\nExiting Now\n");
}
难道我只是暴露wait_int非常直接,然后为所欲为无限循环的蟒蛇相当于成语是什么?还有一些需要解决的问题。我已经在c做了它,但也许它可以被移到python一侧。
答
你不需要在Python方面做任何事情,你可以把它当作一个同步函数。在C方面,你只是阻塞,直到事件发生,可能允许中断。例如,看看在time.sleep
功能的implementation:
/* LICENSE: http://docs.python.org/license.html */
/* Implement floatsleep() for various platforms.
When interrupted (or when another error occurs), return -1 and
set an exception; else return 0. */
static int
floatsleep(double secs)
{
/* XXX Should test for MS_WINDOWS first! */
#if defined(HAVE_SELECT) && !defined(__BEOS__) && !defined(__EMX__)
struct timeval t;
double frac;
frac = fmod(secs, 1.0);
secs = floor(secs);
t.tv_sec = (long)secs;
t.tv_usec = (long)(frac*1000000.0);
Py_BEGIN_ALLOW_THREADS
if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
#ifdef EINTR
if (errno != EINTR) {
#else
if (1) {
#endif
Py_BLOCK_THREADS
PyErr_SetFromErrno(PyExc_IOError);
return -1;
}
}
Py_END_ALLOW_THREADS
#elif defined(__WATCOMC__) && !defined(__QNX__)
...
它所做的就是用select
功能睡的时间一定时间。使用select
,以便如果收到任何信号(例如在终端上按Ctrl + C的SIGINT
),系统调用将中断并且控制返回到Python。
因此。你的实现可以调用C wait_int
函数。如果它支持被信号中断,那么将会允许用户通过按Ctrl + C来中断它,但是要确保做出适当的反应,以便抛出异常(我不确定这是如何工作的,但是它看起来像从顶层函数返回NULL
(在这个例子中为time_sleep
)将做到这一点)。
同样,为了更好的多线程性能,请用一对Py_BEGIN_ALLOW_THREADS
/Py_END_ALLOW_THREADS
宏等待电话,但不是必需的,特别是如果你不使用多线程的。
很简单。而True:wait_int() – tladuke
如果我把它放在python线程中,它会阻塞任何其他线程,直到出现中断为止。 – tladuke
Py_BEGIN_ALLOW_THREADS修正了它。 – tladuke