C中没有线程的非阻塞库API

时间:2018-01-08 13:47:29

标签: c linux multithreading nonblocking synchronous

如何在不使用线程的情况下在c中实现非阻塞库API?

简而言之,我编写了一个库,它通过串行控制器发出一些读/写调用,以便获取库所需的数据。 这些通过专有驱动程序对串行设备的调用是阻塞的,我无法对其进行更改。

我的库中没有使用线程,或者写一个系统服务与我的库共存,有没有办法去#34;包装"我的库API调用所以它们是非阻塞的(即像python中的协同例程)?期望的最终结果是一个简单的,同步的,非阻塞的API调用,以最少的等待来查询库的状态。

谢谢。

3 个答案:

答案 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>。