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
является аналогом для дубля.Что касается планирования, то это планирование по умолчанию.
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
}
Полный код на github , с примером , который показывает, как использовать MVar.
MVar довольно быстрый, если к нему обращается только один поток (и тяжелыйутверждение).Но в условиях сильной конкуренции и множественных потоков (даже двух) масштабируется очень плохо.Это не удивительно, потому что pthreads работает.Я обнаружил, что MVar в Haskell очень хорошо работает с несколькими потоками.Это не удивительно, учитывая, насколько хорошо в GHC реализованы легкие потоки и примитивы параллелизма.