2013-10-09 2 views
2

Псевдокод для «неадекватной реализации» проблемы производителя, упомянутый в wikipedia, приведен ниже. Говорят, что это решение имеет условие гонки, которое может вызвать тупик.Многопоточное программирование - производитель Потребитель

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

int itemCount = 0; 

procedure producer() { 
    while (true) { 
     item = produceItem(); 

     if (itemCount == BUFFER_SIZE) { 
      sleep(); 
     } 

     putItemIntoBuffer(item); 
     itemCount = itemCount + 1; 

     //if (itemCount == 1) <<<<<<<< change this to below condition 
     if(itemCount > 0) 
     { 
      wakeup(consumer); 
     } 
    } 
} 

procedure consumer() { 
    while (true) { 

     if (itemCount == 0) { 
      sleep(); 
     } 

     item = removeItemFromBuffer(); 
     itemCount = itemCount - 1; 

     //if (itemCount == BUFFER_SIZE - 1) <<<<<<< Change this to below 
     if(itermCount < BUFFER_SIZE) 
     { 
      wakeup(producer); 
     } 

     consumeItem(item); 
    } 
} 

ответ

1

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

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

Решение сделать следующее:

lock() { 
    while (itemCount == 0) { 
     sleep(); 
    } 

    item = removeItemFromBuffer(); 
    itemCount = itemCount - 1; 
} 

Таким образом, даже если потребитель пробуждается, он сразу проверяет снова что itemCount не является 0 с while цикла. Несмотря на то, что значение itemCount было увеличено, другой поток мог бы удалить этот элемент и уменьшился itemCountдо поток, получивший сигнал, имел шанс действовать. Это гонка.

Это то же самое для стороны производителя, хотя гонка должна остановить продюсер от чрезмерного заполнения буфера. Продюсер может быть разбужен, потому что есть свободное место, но к тому времени, когда он идет, чтобы поместить элементы в буфер, другие потоки избили его и повторно заполнили буфер. Он должен снова протестировать, чтобы убедиться, что после того, как он проснулся, есть место.

Я подробно расскажу об этой гонке на этой странице с моего сайта под названием Producer Consumer Thread Race Conditions. Там также есть небольшая тестовая программа, которая демонстрирует проблему.

Важным моментом для реализации является то, что в большинстве реализаций блокировки существует очередь потоков, ожидающих получения доступа к блокировке. Когда сигнал отправляется в нить, он сначала должен reacquire замок, до он может продолжаться. Когда поток сигнализируется, он переходит к концу очереди BLOCK. Если есть дополнительные потоки, которые ждут блокировки, но не ожидания, они будут бежать впереди пробужденной нити и украсть предметы.

Это очень похоже на вопрос о while петлях в аналогичном коде. К сожалению, принятый ответ не касается этого состояния гонки. Пожалуйста, подумайте о том, чтобы выжить my answer to a similar question here. Поддельные пробуждения - это проблема, но настоящая проблема здесь - это состояние гонки, о котором говорит википедия.

+1

Также все строки, которые изменяют 'itemCount', должны быть атомарными или заблокированными. – Adam

+0

Просто исправлено это @Adam. Благодарю. – Gray

+0

В случае с несколькими потребителями-производителями не следует посылать пробуждения во все темы? Таким образом, можно избежать гонки? – goldenmean

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