C中是否有任何已知的Haskell MVar
实现?关于如何在C ++中实现它有一个example。但是,我想在C中实现它 - 我们现在只说C中的MVar CInt
等价物。编写同步原语可能很棘手。所以,如果有人已经做过,我希望避免重复劳动。我不太了解上面的C ++示例,可以自信地将其转换为C - 它很好地隐藏了我的C ++中的算法细节 - 缺乏经验的头脑:)
我在考虑在C中编写MVar的原因是因为它使我很容易使用FFI绑定到外部C库来获取数据流,并使用Haskell线程来获取数据(来自Storable避免编组数据的向量 - 这里的MVar CInt存储了多少可存储的向量。我需要确保在Haskell线程读取数据时阻塞写入Storable位置的C线程。这就是C侧的MVar同步有帮助的地方。从Haskell调用不安全甚至安全的C函数(在我的测试中安全性约为15ns,在测试中安全性约为150ns)比从C调用Haskell(~5us)要快得多。如果回调很快,我会将C函数调用回Haskell,并阻塞Haskell MVar。
更新
伪代码中的算法也可以。考虑到newEmptyMVar,takeMVar和putMVar的算法,在C中实现它应该很容易。
答案 0 :(得分:4)
可以使用如下结构在C中实现MVar:
typedef struct{
pthread_cond_t put_cond;
pthread_cond_t take_cond;
pthread_mutex_t lock;
void* value;
} mvar;
put_cond
由线程使用,这些线程在MVar中放置值以指示等待从MVar获取值的其他线程。 take_cond
是类似的对应物。至于调度,它是默认调度。
value
是一个void指针 - 所以,上面的结构可以用来保护MVar中的任何类型的值 - 当然,C会让你把指针写在MVar之外 - 所以,它是程序的确保不会发生这种情况的责任(通过避免在MVar之外躲开value
指针 - 始终通过MVar函数访问它。)
初始化MVar
:
mvar* newMVar(void* arg){
//create new mvar struct
mvar* var=(mvar*) malloc(sizeof(mvar));
pthread_mutex_init(&var->lock,NULL);
pthread_cond_init(&var->take_cond,NULL);
pthread_cond_init(&var->put_cond,NULL);
var->value = arg;
return (mvar*) var;
}
空MVar
- 使用以上功能:
mvar* newEmptyMVar(){
return newMVar(NULL);
}
putMVar
:
void putMVar(mvar* var,void* value){
pthread_mutex_lock(&var->lock);
while(var->value != NULL)
pthread_cond_wait(&var->put_cond,&var->lock);//if MVar is full, wait until another thread takes the value - release the mutex, and wait on put_cond to become true
var->value = value;//if here, we got the signal from another thread that took MVar - MVar is empty now. OK to fill
pthread_cond_signal(&var->take_cond);//signal other threads that value is available for taking now
pthread_mutex_unlock(&var->lock);
}
takeMVar
:
void* takeMVar(mvar* var){
void* value;
pthread_mutex_lock(&var->lock);
while(var->value == NULL)
pthread_cond_wait(&var->take_cond,&var->lock);//if MVar is empty, wait until another thread fills it - release the mutex, and wait on take_cond to become true
//take the value
value = var->value;
var->value = NULL; //push NULL value to indicate MVar is empty now
pthread_cond_signal(&var->put_cond);//signal other threads that value is available for filling now
pthread_mutex_unlock(&var->lock);
return value; //return the value that was taken from MVar
}
如果只有一个线程访问它(并且争用很多),那么MVar会非常快。但是,在激烈的争用和多线程(甚至两个)之间,它的扩展性非常差。由于pthreads的工作方式,这并不奇怪。我发现Haskell中的MVar非常适合多线程。考虑到在GHC中实现轻量级线程和并发原语的效果,这并不奇怪。
答案 1 :(得分:0)
示例中的代码不是特定于C ++的。基本位正好是pthread
- 片段。