阻塞调用后立即调用方法

Posted

技术标签:

【中文标题】阻塞调用后立即调用方法【英文标题】:Call method right after blocking call 【发布时间】:2012-06-22 20:34:47 【问题描述】:

我正在使用具有阻塞功能的第三方库,也就是说,它在完成之前不会返回;我可以为该呼叫设置超时。

问题是,该函数将库置于某种状态。一旦它进入那个状态,我需要用我自己的代码做一些事情。我的第一个解决方案是在单独的线程中执行此操作:

void LibraryWrapper::DoTheMagic()
    //...
    boost::thread EnteredFooStateNotifier( &LibraryWrapper::EnterFooState, this );
    ::LibraryBlockingFunction( timeout_ );
    //...


void LibraryWrapper::EnterFooState()
   ::Sleep( 50 ); //Ensure ::LibraryBlockingFunction is called first
   //Do the stuff

很恶心,不是吗?我必须拨打 Sleep 电话,因为 ::LibraryBlockingFunction 必须在我下面做的事情之前被调用,否则一切都会失败。但是等待 50 毫秒是一个很差的保证,我不能再等了,因为这个特定的任务需要尽快完成。

难道没有更好的方法吗?考虑到我无权访问图书馆的代码。欢迎使用 Boost 解决方案。

更新:就像其中一个答案所说,库 API 定义不明确。我向开发人员发送了一封电子邮件,解释了问题并提出了解决方案(即,使呼叫成为非阻塞并将事件发送到已注册的回调以通知状态更改)。同时,我将超时设置得足够高以确保 X 完成,并在执行调用后工作之前设置足够高的延迟以确保调用库函数。它不是确定性的,但在大多数情况下都有效。

【问题讨论】:

我很困惑。为什么你不能做显而易见的事情,而在阻塞调用返回后只做你必须做的事情?为什么是第二个线程? @John:我将问题解释为需要在调用之后但在它返回之前更改状态。不过我可能是错的...... @John:就像亚历克斯说的那样。我需要尽快完成(硬件) 它是否必须严格地发生在您进入阻塞调用之后和阻塞调用返回之前的时间之间? @John:是的。让我给你更多细节:阻塞功能将硬件 A 置于状态 S 一段时间。在那个状态下,它期望硬件 B 做 X 的事情。为了这个过程成功,B 必须在 A 处于 S 状态时对 A 执行 X。如果我为 A 和 B 有单独的库,这将很容易,但是这个库控制它们,而我对 B 所做的事情是通过软件调用的临时硬件解决方案。 【参考方案1】:

使用 boost future 会澄清这段代码吗?使用boost future documentation 中的示例:

int calculate_the_answer_to_life_the_universe_and_everything()

    return 42;


boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::unique_future<int> fi=pt.get_future();

boost::thread task(boost::move(pt));

// In your example, now would be the time to do the post-call work.

fi.wait(); // wait for it to finish

尽管您可能仍然需要一些延迟以确保您的函数调用已经发生(您的这个问题似乎定义不明确 - 有什么方法可以确定何时可以安全执行通话后状态变化?)。

【讨论】:

哇,这看起来很有趣,+1。我将开始阅读 Boost 的未来。关于延迟,我只知道LibraryBlockingFunction 必须运行才能进行通话后更改。我与库开发人员保持密切联系,因此我可以要求更改 API,但可能需要一些时间。【参考方案2】:

据我了解,问题是您需要这样做:

    输入阻塞调用 在进入阻塞调用之后但在它完成之前,你需要做一些其他的事情 您需要在阻塞调用返回之前完成#2

从纯粹的 C++ 角度来看,您无法以确定性的方式实现这一点。那是在不了解您正在使用的库的详细信息的情况下。

但我注意到了你的超时值。这可能会提供一个漏洞,也许。

如果你:

    输入超时为零的阻塞调用,使其立即返回 你有其他的东西吗,要么在同一个线程中,要么与主线程同步。也许使用屏障。 验证 #2 完成后,再次进入阻塞调用,正常的非零超时。

只有当你进入零超时的阻塞调用时库的状态会发生变化,这才会起作用。

【讨论】:

无法将超时设置为零:这意味着硬件 A 根本不会等待硬件 B 的操作;超时与硬件 A 保持在状态 S 的时间相关联,等待 X 发生。

以上是关于阻塞调用后立即调用方法的主要内容,如果未能解决你的问题,请参考以下文章

同步异步阻塞非阻塞 总结

同步与异步并发和并行阻塞和非阻塞

IO模型介绍

Python-异步编程

页面加载后如何立即调用javascript方法[重复]

十异步