是否有任何已知的 Haskell MVar
用 C 实现?有一个关于如何在 C++ 中实现它的示例。但是,我想用 C 实现它 - 现在我们只说 C 中的 MVar CInt 等效项。编写同步原语可能很棘手。因此,如果有人已经这样做了,我希望避免重复工作。我对上面的 C++ 示例理解不够充分,无法自信地将其翻译为 C - 它很好地隐藏了我没有 C++ 经验的头脑中的算法细节:)
我考虑用 C 编写 MVar 的原因是因为它使它变得非常容易对我来说,使用 FFI 绑定到外部 C 库来获取数据流,并使用 Haskell 线程来获取数据(从可存储向量中获取数据,以避免封送数据 - MVar CInt 这里存储了多少数据)可存储向量已被填充)。我需要确保在 Haskell 线程读取数据时,写入可存储位置的 C 线程被阻止。这就是 C 端 MVar 同步的帮助之处。从 Haskell 调用不安全甚至安全的 C 函数(在我的测试中,不安全约 15 纳秒,安全约 150 纳秒)比从 C 回调到 Haskell(约 5 秒)要快得多。如果回调速度很快,我会让 C 函数回调回 Haskell,并阻止 Haskell MVar。
更新:
伪代码算法也可以。考虑到 newEmptyMVar、takeMVar 和 putMVar 的算法,用 C 语言实现它应该很容易。
Is there any known implementation of Haskell MVar
in C? There is an example on how to implement it in C++. But, I will like to implement it in C - let us say only MVar CInt
equivalent in C for now. Writing synchronization primitives can be tricky. So, I will like to avoid duplication of effort if someone has already done it. I didn't understand the C++ example above well enough to confidently translate it into C - it hides the algorithmic details very well from my C++-inexperienced mind :)
The reason I am thinking about writing MVar in C is because it makes it really easy for me to use the FFI binding to an external C library to get the stream of data, and use Haskell threads to grab the data (from Storable vectors to avoid marshaling the data - MVar CInt here stores how much of the Storable vectors have been filled). I need to make sure that C threads writing to Storable locations are blocked while a Haskell thread is reading the data. That is where MVar synchronization on C side helps. It is also much faster to call unsafe or even safe C function from Haskell (~15ns for unsafe, ~150ns for safe in my test), than callback into Haskell from C (~5us). If callbacks were fast, I would have had C function call back into Haskell instead, and block on Haskell MVar.
Update:
Algorithm in pseudo-code will do as well. It should be quite easy to implement it in C, given the algorithm for newEmptyMVar, takeMVar and putMVar.
发布评论
评论(2)
MVar 可以使用如下结构在 C 中实现:
put_cond
由将值放入 MVar 的线程使用,以向其他正在等待从 MVar 获取值的线程发出信号。take_cond
是 take 的类似对应项。至于调度,是默认调度。value
是一个 void 指针 - 因此,上述结构可用于保护 MVar 中的任何类型的值 - 当然,C 会让您在 MVar 之外写入该指针 - 所以,它是程序的有责任确保这种情况不会发生(通过避免将value
指针隐藏在 MVar 之外 - 始终通过 MVar 函数访问它)。初始化
MVar
:空
MVar
- 使用上述函数:putMVar
:takeMVar
:完整代码位于 github,带有 示例展示了如何使用 MVar。
如果只有一个线程访问它(并且争用很严重),MVar 会相当快。但是,在激烈的争用和多个线程(甚至两个)的情况下,它的扩展性非常差。鉴于 pthread 的工作方式,这并不奇怪。我发现 Haskell 中的 MVar 对于多线程非常有用。考虑到 GHC 中轻量级线程和并发原语的实现有多好,这并不奇怪。
MVar can be implemented in C using a struct like below:
put_cond
is used by threads that put values in MVar to signal other threads that are waiting to take value from MVar.take_cond
is the analogous counterpart for take. As for scheduling, it is default scheduling.value
is a void pointer - so, the above structure can be used to protect any type of value in an MVar - of course, C will let you write that pointer outside MVar - so, it is the program's responsibility to ensure this doesn't happen (by avoiding squirreling awayvalue
pointer outside MVar - always access it through MVar functions).Initializing
MVar
:Empty
MVar
- uses above function:putMVar
:takeMVar
:Complete code is on github, with example which shows how to use MVar.
MVar is quite fast if there is only one thread accessing it (and heavy contention). But, under heavy contention, and multiple threads (even two), it scales very poorly. This is not a surprise because of the way pthreads work. I have found MVar in Haskell to be very good with multiple threads. This is not a surprise given how well lightweight threads and concurrency primitives are implemented in GHC.
示例中的代码不太特定于 C++。基本位正是 pthread 片段。
The code in the example is not very C++-specific. The essential bits are exactly the
pthread
-fragments.