【问题标题】:Implementation of MVar in C?MVar 在 C 中的实现?
【发布时间】:2012-02-12 20:55:53
【问题描述】:

在 C 中是否有任何已知的 Haskell MVar 实现?有一个 example 关于如何在 C++ 中实现它。但是,我想在 C 中实现它——让我们现在只说在 C 中等效的 MVar CInt。编写同步原语可能很棘手。所以,如果有人已经做过,我想避免重复工作。我对上面的 C++ 示例理解得不够好,无法自信地将其翻译成 C - 它很好地隐藏了我没有 C++ 经验的算法细节:)

我考虑用 C 编写 MVar 的原因是因为它使我可以很容易地使用 FFI 绑定到外部 C 库来获取数据流,并使用 Haskell 线程来获取数据(来自 Storable向量以避免封送数据 - 此处的 MVar CInt 存储已填充多少可存储向量)。我需要确保在 Haskell 线程读取数据时,写入可存储位置的 C 线程被阻塞。这就是 C 端的 MVar 同步有帮助的地方。从 Haskell 调用不安全甚至安全的 C 函数(在我的测试中为不安全约 15ns,为安全约 150ns)也比从 C 回调到 Haskell(约 5us)要快得多。如果回调速度很快,我会改为将 C 函数调用回 Haskell,并阻止 Haskell MVar。

更新:

伪代码中的算法也可以。考虑到 newEmptyMVar、takeMVar 和 putMVar 的算法,用 C 语言实现它应该很容易。

【问题讨论】:

  • 对于那些不熟悉 Haskell 的MVar,请参阅:Control.Concurrent.MVar
  • 我无法帮助您解决您的问题,但是您从哪里得到时间在 Haskell 和 C 之间进行外部通话。昨天,我一直在徘徊如何使用标准进行基准测试。
  • @jmg,这里的代码(对于 haskell->C):hpaste.org/56609。那里没有标准基准,但应该很简单,结果应该非常接近。对于 C->Haskell 回调,请参阅这篇文章中的代码:stackoverflow.com/questions/8902568/…

标签: c haskell synchronization ffi


【解决方案1】:

示例中的代码不是 C++ 特定的。基本位正是pthread-fragments。

【讨论】:

    【解决方案2】:

    MVar 可以使用如下结构在 C 中实现:

    typedef struct{
      pthread_cond_t put_cond;
      pthread_cond_t take_cond;
      pthread_mutex_t lock;
      void* value;
    } mvar;
    

    put_cond 被将值放入 M​​Var 的线程用来向其他线程发出信号,这些线程正在等待从 MVar 获取值。 take_cond 与 take 类似。至于调度,是默认调度。

    value 是一个 void 指针 - 因此,上述结构可用于保护 MVar 中的任何类型的值 - 当然,C 将允许您在 MVar 之外写入该指针 - 因此,程序负责确保不会发生这种情况(通过避免将 value 指针移到 MVar 之外 - 始终通过 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
    }
    

    完整代码在githubexample 显示如何使用 MVar。

    如果只有一个线程访问它(并且竞争很激烈),MVar 会非常快。但是,在激烈的争用和多个线程(甚至两个)的情况下,它的扩展性很差。由于 pthread 的工作方式,这并不奇怪。我发现 Haskell 中的 MVar 非常适合多线程。考虑到轻量级线程和并发原语在 GHC 中的实现非常好,这不足为奇。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 2015-09-03
      • 2019-07-20
      • 2011-03-01
      • 2021-04-17
      相关资源
      最近更新 更多