2012-01-18 2 views
9

C에서 Haskell MVar의 알려진 구현이 있습니까? C++로 구현하는 방법에는 example이 있습니다. 하지만 C 언어로 구현하고 싶습니다. C 언어에서는 MVar CInt과 동등합니다. 동기화 기본 요소 작성은 까다로울 수 있습니다. 그래서, 누군가가 이미 그것을했다면 나는 노력의 중복을 피하고 싶습니다. 위의 C++ 예제를 자신있게 C 언어로 변환 할 수 없다는 것을 이해하지 못했습니다. C++에서 알고리즘 세부 정보를 잘 숨 깁니다.C에서 MVar 구현?

C에서 MVar를 작성하려고 생각한 이유는 FFI 바인딩을 사용하여 외부 C 라이브러리를 사용하여 데이터 스트림을 얻고 Haskell 스레드를 사용하여 데이터를 가져옵니다 (데이터 마샬링을 방지하기 위해 Storable 벡터에서 가져 오기 - MVar CInt는 Storable 벡터가 채워짐). 하스켈 스레드가 데이터를 읽는 동안 Storable 위치에 쓰는 C 스레드가 차단되는지 확인해야합니다. 이것이 C 측의 MVar 동기화가 도움이되는 곳입니다. Haskell에서 C (~ 5us) 콜백보다 하스켈에서 안전하지 않거나 안전한 C 함수를 호출하는 것이 훨씬 빠릅니다 (안전하지 않은 경우 15ns, 내 테스트에서 안전 할 때 150ns). 콜백이 빠르다면 C 함수가 Haskell에 대신 콜백하고 Haskell 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은 void 포인터입니다. 위의 구조는 MVar에서 모든 유형의 값을 보호하는 데 사용할 수 있습니다. 물론 C는 MVar 외부에서 해당 포인터를 쓸 수있게합니다. 이것은 일어나지 않습니다 (포인터가 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는 스레드에 액세스하는 스레드가 하나 (무거운 경합) 인 경우 매우 빠릅니다. 그러나 무거운 경합과 여러 스레드 (두 개조차도)에서는 매우 저조한 확장이 가능합니다.이것은 pthreads가 작동하는 방식 때문에 놀랄 일이 아닙니다. 하스켈의 MVar가 여러 스레드에서 매우 잘 작동한다는 것을 알았습니다. GHC에서 가벼운 쓰레드와 동시성 프리미티브가 얼마나 잘 구현되었는지는 놀랄 일이 아닙니다.

0

예제의 코드는 C++에만 한정되지 않습니다. 필수 비트는 정확히 pthread 조각입니다.