2012-01-18 11 views
9

CにHaskell MVarの実装はありますか? C++で実装する方法については、exampleがあります。しかし、私はそれをC言語で実装したいと思います - 今のところC言語ではMVar CIntと同等です。同期プリミティブの作成は難しいことがあります。だから誰かがすでにそれをやっているなら、私は努力の重複を避けたいと思う。私は上記のC++の例をC言語に自信を持って翻訳することはできませんでした.C++の経験の浅い方からアルゴリズムの詳細をうまく隠しています:)CでのMVarの実装?

私はMVarをC言語に書いていると思っていますFFIバインディングを使用して外部のCライブラリを使用してデータストリームを取得し、Haskellスレッドを使用してデータを取得します(データのマーシャリングを避けるためにStorableベクトルから取得します)。MVarここでは、Storableベクトルが満たされている)。 Haskellスレッドがデータを読み込んでいる間に、Storableの場所に書き込んだCスレッドがブロックされていることを確認する必要があります。これは、C側のMVar同期が役立つところです。 CからのHaskell(〜5us)へのコールバックよりも、Haskellからの安全でないC関数(安全でないことは〜15ns、私のテストでは安全には〜150ns)を呼び出す方がはるかに高速です。コールバックが速ければ、私はC関数をハスケルに戻し、ハスケルMVarでブロックすることになりました。

更新:擬似コードで

アルゴリズムも同様に行います。 newEmptyMVar、takeMVar、putMVarのアルゴリズムが与えられているので、Cで実装するのはかなり簡単です。

+1

ハスケルの 'MVar'に慣れていない人は、[Control.Concurrent.MVar](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Concurrent-MVar)を参照してください。 html) –

+0

私はあなたの質問であなたを助けることはできませんが、どこでHaskellとCの間の外貨呼出しの時間を得ましたか。昨日、私は基準を使用してそれをベンチマークする方法をさまよっていました。 – jmg

+0

@jmg、コードはこちら(haskell-> C):http://hpaste.org/56609。そこではベンチマークを行う基準はありませんが、実行するのは非常に簡単で、結果はかなり近いはずです。 C-> Haskellコールバックについては、この記事のコードを参照してください:http://stackoverflow.com/questions/8902568/runtime-performance-degradation-for-c-ffi-callback-when-pthreads-are-enabled – Sal

答えて

3

MVARは、以下のような構造体を使用して、Cで実装することができる。

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はtakeの類似のものです。スケジューリングに関しては、デフォルトのスケジューリングです。

valueは無効なポインタなので、上記の構造は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 
} 

完全コードはgithubで、exampleはMVarの使い方を示しています。

MVarは、それにアクセスするスレッドが1つしかない場合(および重い競合の場合)は非常に高速です。しかし、重い競合や複数のスレッド(2つでも)の下では、非常にうまく調整できません。これは、pthreadsの仕組みのために驚くことではありません。私はHaskellのMVarが複数のスレッドで非常に優れていることを発見しました。これはGHCで軽量スレッドと同時実行プリミティブがどの程度うまく実装されているかを考えると驚くことではありません。

0

この例のコードはC++固有のものではありません。本質的なビットはちょうどpthread - 断片です。