我主要使用 .NET 进行编程,我喜欢它的异步/并发原语,例如 Tasks、ResetEvents 等。今天,我第一次对 C++ 程序进行了有意义的更改,并了解了整个构建过程是如何工作的(我更新了 LigthningDB.NET 项目至 0.9.14)。但我仍然缺乏 C++ 知识。
我想添加到 LMDB 项目中的一个新功能(出于我自己的需要)是通知系统(类似于 Redis):
- 我想要一个游标返回一个等待对象,该对象将在其表中的每个数据更改时发出信号。
- 我想将一些数据与信号(指向数据结构的指针)一起获取,例如键或键+值。
- 该对象将与游标一起放置,并且是游标的一部分,但它会在游标具有引用的 DB 中发出更改信号。
- 这必须有一天(或某年)跨平台工作。如果他们完成这项工作,我可以接受任何肮脏的 Windows 特定的黑客攻击。
典型的用例是一个作家和 N 个读者在等待新消息。这将允许 IPC 和快速持久性二合一。LMDB 支持从不同进程并发读取(而 Esent 和 LevelDB 不支持)。
System.Threading
原语可从 C++ 获得,我了解如何使用 WaitHandle 进行阻塞调用。有没有办法使这个异步?有很多关于异步同步原语的文章,但它们使用TaskCompletionSource
并且仅在 .NET 内部有效。是否可以为本机互操作制定类似的解决方案?
一种解决方案可能是命名管道或套接字将更改转换为一个侦听器/调度程序(Redis 或Rhino.Queues样式),但性能会受到影响:写入必须分配、复制和推送数据,并且数据必须传输——比传递更糟糕指向已经在内存中的数据结构的指针。
另一种选择是将聆听光标移动到键并发送信号。发出信号后,C# 侦听器将知道光标在更新的键处具有值。这种方法解决了数据传输部分,但是使用 WaitHandles 它是阻塞的——在我的用例中阻塞比套接字 [分配/复制/延迟] 组合更糟糕。
有更好的选择吗?
附加问题:
- 我在这里重新发明自行车吗?
- 您能否指出.NET 程序等待(非阻塞)C/C++ 信号(如果存在)的开源库?
- 我应该为该工作流程使用 LMDB 吗?Windows 是我的优先事项,我在尝试让 LevelDB 工作时遇到了非常糟糕的时间(停止尝试)。对于 LMDB 所做的一切 + 信令,是否有更好的选择?
更新
我在文档中找到了这个方法:
public static Task WaitOneAsync(this WaitHandle waitHandle)
{
if (waitHandle == null) throw new ArgumentNullException("waitHandle");
var tcs = new TaskCompletionSource<bool>();
var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
delegate { tcs.TrySetResult(true); }, null, -1, true);
var t = tcs.Task;
t.ContinueWith(_ => rwh.Unregister(null));
return t;
}
的文档ThreadPool.RegisterWaitForSingleObject
说:
等待操作由线程池中的一个线程执行。当对象的状态变为信号或超时间隔过去时,工作线程将执行委托。...等待线程使用 Win32 WaitForMultipleObjects函数来监视已注册的等待操作。
我是否正确,这是两个不同的线程,如果没有信号,第一个等待线程是唯一会阻塞的线程?