2015-01-28 7 views
0

Я проходил через this и this. В основном, они обсуждают, почему классический однопоточный потребительский дизайн производителя (с signal и wait не работает для многопрофильного сценария). У меня есть одно сомнение, которое прослушивал меня -pthread_mutex_wait несколько производителей и потребителей

Аргумент сделанный автором
Рассмотрим код ссылки

char queue[MAX]; //global 
int head = 0, tail = 0; //global 
struct cv not_full, not_empty; 
struct lock qlock; 

void produce(char data) { 
    acquire(&qlock); 
    if ((head + 1) % MAX == tail) { 
    wait(&not_full, &qlock); //line 1 
    } 
    queue[head] = data; //line 2 
    head = (head + 1) % MAX; 
    notify(&not_full); 
    release(&qlock); 
} 

char consume(void) { 
    acquire(&qlock); 
    if (tail == head) { 
    wait(&not_empty, &qlock); 
    } 
    e = queue[tail]; 
    tail = (tail + 1) % MAX; 
    notify(&not_empty); 
    release(&qlock); 
    return e; 
} 

В приведенном выше коде, в случае двух производителя, line 1 будет woken up в обоих нить производителя одним потребителем (когда очередь не заполнена). Таким образом, оба производителя могут добавить в очередь, что приведет к переполнению очереди.

Мои сомнения
a. Мы защищаем очередь с блокировкой мьютекса. Таким образом, даже если wait разбудится на нескольких потоках производителей, только один производитель все равно будет блокировать мьютексы - поэтому логически для добавления в очередь будет принадлежать только один владелец. Потому что, когда мы выходим из wait, у нас есть мьютекс, который будет приобретен.

Cavet
Я использую POSIX семафор, Cond вар в качестве ссылки. Тем не менее, я не вижу статьи, написанные с POSIX в качестве эталонного стандарта.

Вопрос
ли мое понимание wait конкретно pthread_cond_wait правильно? И с несколькими производителями целостность кода сохраняется.

+0

вы на самом деле означает 'pthread_mutex_wait' или вы имеете в виду' pthread_cond_wait'? – UmNyobe

+0

@UmNyobe: Правильно я бы отредактировал его. –

+0

Я не уверен в вашем конкретном вопросе, но ваш код будет работать с несколькими производителями/потребителями, если вы преобразуете два оператора 'if' в операторы' while' и используете pthread_cond_broadcast в качестве примитива notify(). Но как есть, риск кода взрывается. – nos

ответ

1

Автор упоминался в конце своей статьи под семантикой ожидания() и уведомить() что

уведомит (резюме) просыпается всех темы, которые в настоящее время ожидание на том, что резюме

Так ваше понимание ждать неверен, notify предназначается, чтобы быть в POSIX pthread_cond_broadcast.

Кроме того, предусматривается documentation of pthread_cond_signal

pthread_cond_signal() вызова разблокирует по меньшей мере, один из нитей , которые заблокированы от переменной конд заданного условия (если какие-либо потоков блокируются на Cond).

Что по-прежнему отличается от вашего «только один производитель» предположение.

Как показал автор, целостность вышеуказанного кода не поддерживается несколькими производителями.

редактировать:

pseudocode of a condition variablewait может выглядеть

void wait (condition *cv, mutex *mx) 
{ 
    mutex_acquire(&c->listLock); /* protect the queue */ 
    enqueue (&c->next, &c->prev, thr_self()); /* enqueue */ 
    mutex_release (&c->listLock); /* we're done with the list */ 

    /* The suspend and release_mutex() operation should be atomic */ 
    release_mutex (mx)); 
    thr_suspend (self); /* Sleep 'til someone wakes us */ 

    <-------- notify executes somewhere else 

    mutex_acquire (mx); /* Woke up -- our turn, get resource lock */ 
    return; 
} 

во время signal по меньшей мере, одной нити в очереди в suspend состоянии пробудиться. Но pthread не гарантирует будет только один. Теперь они управляемы. Но им по-прежнему необходимо приобрести замок, чтобы обеспечить взаимное исключение между собой.

Итак, когда первый релиз мьютекса, второй берет его и так далее.

Это означает, что один за другим Awaken производители будут выполнять

queue[head] = data; //line 2 
head = (head + 1) % MAX; 
notify(&not_full); 
release(&qlock); 
+1

Предположим, что пробурено более одного потока, тогда будет приобретен мьютекс - который должен быть приобретен только одним из них - правильным? Вот где я смущаюсь. Не гарантирует ли мьютекс, даже если многие из них разбужены - pthread_cond_wait (который с атомарным захватом при выходе) должен привести к тому, что только один поток действительно проснулся. –

+0

@kumar_m_kiran добавил дополнительные пояснения – UmNyobe

+0

Блестящий! Благодаря! –

Смежные вопросы