如何在不使用线程的情况下在c
中实现非阻塞库API?
简而言之,我编写了一个库,它通过串行控制器发出一些读/写调用,以便获取库所需的数据。 这些通过专有驱动程序对串行设备的调用是阻塞的,我无法对其进行更改。
我的库中没有使用线程,或者写一个系统服务与我的库共存,有没有办法去#34;包装"我的库API调用所以它们是非阻塞的(即像python中的协同例程)?期望的最终结果是一个简单的,同步的,非阻塞的API调用,以最少的等待来查询库的状态。
谢谢。
答案 0 :(得分:4)
简答:不。
您无法更改延迟,因为它是所请求的操作所固有的(发送数据需要一定的时间),因此您无法缩短通话时间。
因此,您可以选择等待呼叫完成或不等待呼叫。
你不能在没有某种线程的情况下跳过等待它,因为这就是处理器一次性暴露它的抽象的方式(即在串口上发送数据和继续使用更多代码)...因此你需要线程来实现这一点。
答案 1 :(得分:1)
我认为首先你应该改变你的lib,使所有的呼叫都无阻塞。这是一个很好的解释Linux Blocking vs. non Blocking Serial Read
C语言中python协同例程的最接近的技巧是Protothread。它实现了简单的协作式多任务处理而不使用线程
答案 2 :(得分:0)
通常最好使用线程来执行此操作。 但是,有一种方法可以解决简单应用程序的局限性。
请原谅使用C ++ 11 lambda,我认为这使这里的内容更清楚了。
namespace
{
sigjmp_buf context;
} // namespace
void nonBlockingCall(int timeoutInSeconds)
{
struct sigaction* oldAction = nullptr;
struct sigaction newAction;
if (sigsetjmp(::context,0) == 0)
{
// install a simple lambda as signal handler for the alarm that
// effectively makes the call time out.
// (e.g. if the call gets stuck inside something like poll() )
newAction.sa_handler = [] (int) {
siglongjmp(::context,1);
};
sigaction(SIGALRM,&newAction,oldAction);
alarm(timeoutInSeconds); //timeout by raising SIGALM
BLOCKING_LIBRARY_CALL
alarm(0); //cancel alarm
//call did not time out
}
else
{
// timer expired during your call (SIGALM was raised)
}
sigaction(SIGALRM,oldAction,nullptr);
}
限制:
这对于多线程代码是不安全的。 如果您有多线程代码,最好将计时器放在 监视线程,然后杀死被阻止的线程。
计时器和其他地方的信号可能会干扰。
除非BLOCKING_LIBRARY_CALL很好地记录了其行为,否则您可能处于未定义的行为领域。
如果在C ++中而不是在C ++中使用此惯用语,则必须不允许在setjmp和longjmp之间构造或销毁任何对象。
其他人可能还会发现这个习语的其他问题。
我以为我在Steven's的某个地方看到过此消息,确实在信号一章中对此进行了讨论,该章讨论了使用 alarm()实现 sleep()< / em>。