【问题标题】:Blocking code and callbacks. How to to transform blocking code in non-blocking code?阻塞代码和回调。如何在非阻塞代码中转换阻塞代码?
【发布时间】:2021-09-19 04:51:56
【问题描述】:

我觉得这个问题的核心和我使用的具体语言和库无关,所以我使用了一些伪代码。我们可以假设 C 是一种语言和一个 WinApi COM DLL。

假设我正在使用一个动态链接的外部库,它公开了一些回调以响应某些事件。说:

function RegisterCallback(ptr *callback);

用作:

function OnEvent(type newValue) {
    ...
}

...
RegisterCallback(&OnEvent)
...

库告诉我回调应该是非阻塞。 现在,假设我想更新一个内部状态来响应这个事件。此内部状态由其他线程访问,因此由 mutex 保护。因此我想写:

function OnEvent(type newValue) {
    mutexLock();
    internalState = newState;
    mutexUnlock()
}

但是,这将是一个潜在的阻塞操作。我应该如何进行?我看到的唯一解决方案是使用不同的线程来更新状态,例如:

function OnEvent(type newValue) {
    sendChangeStateMessage(newValue)
}

但是,同样,为了让这个调用是非阻塞的,这个“发送操作”应该被缓冲(即,有一个消息队列),因为跨线程发送(即共享数据)需要同步,并且因此锁定。

编辑:当然,如果操作是原子的(可能是整数),则没有这样的问题 /EDIT

总结一下:如何将阻塞代码转换为非阻塞代码?

谢谢

【问题讨论】:

  • 这最终是 C++20 协程解决的问题。如果您需要在 C 中实现这一点,您将不得不重新实现协程。
  • 没有什么需要改变的。代码不等待回调中的某些东西
  • @RbMm 见答案下方的评论

标签: multithreading winapi callback blocking nonblocking


【解决方案1】:

使用互斥锁进行锁定并不总是阻塞操作。

如果互斥锁仅用于保护对该变量的访问,并且如果获取该互斥锁的所有其他线程在互斥锁锁定时不执行任何阻塞操作,则这不是阻塞操作。阻塞操作是一种阻塞直到发生某些事情的操作。在这种情况下,这种互斥锁的使用不太可能是阻塞的,除非您将互斥锁锁定在另一个线程中并等待网络读取。

【讨论】:

  • 感谢您的回复,并为迟到的回复感到抱歉,这是我尽可能做的一个副项目。对我来说,这个“阻塞”的定义似乎很主观。互斥锁在设计上是阻塞的,直到它被解锁。也许我明白你的意思:如果我以正确的方式设计我的程序,则不会发生这种阻塞,因此我可以说在实践中,这段代码是非阻塞的。我说的对吗?
  • @EmarJ - 如果我以正确的方式设计程序 - 是的。即使 mutexLock(); 导致等待 - 这将是非常短暂的等待。几乎所有的 api 在内部都使用这种“阻塞”代码。例如,简单地从堆中分配内存 - 你是否理解在内部这也是在关键部分/srw 锁上使用一些等待来获得对堆的独占访问权限?
  • @RbMm 是的,我想我明白了。感谢您的澄清
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
相关资源
最近更新 更多