Многочисленная проблема кода производителя / потребителя и критического раздела - PullRequest
0 голосов
/ 11 сентября 2009

Я пытаюсь решить проблему с множеством производителей / потребителей в C, но она не работает должным образом. Ниже приведен псевдокод, представляющий мою реализацию.

Thread thread1;
Thread thread2;
Thread thread3;

Data data1;
Mutex data1_mutex;
Semaphore data1_empty;
Semaphore data1_fill;

Data data2;
Mutex data2_mutex;
Semaphore data2_empty;
Semaphore data2_fill;

thread1()
{
   // creates data and places it into data1.

   wait(data1_empty);
   lock(data1_mutex);

   // critical section

   unlock(data1_mutex);
   post(data1_fill);
}

thread2()
{
   // Removes data from data1, processes it, and places it into data2.

   // data1
   wait(data1_fill);
   lock(data1_mutex);

   // data2
   wait(data2_empty);
   lock(data2_mutex);

   // critical section

   // data2
   unlock(data2_mutex);
   post(data2_fill);

   // data1
   unlock(data1_mutex);
   post(data1_empty);
}

thread3()
{
   // Removes data from data2, prints its results, and removes it.

   wait(data2_fill);
   lock(data2_mutex);

   // critical section

   unlock(data2_mutex);
   post(data2_empty);
}

Однако, с этим решением данные1 будут заполняться, но поток 2 будет блокироваться и никогда не будет работать. Что-то не так с моей реализацией?

РЕДАКТИРОВАТЬ # 1

Одна из проблем, которые я обнаружил, заключалась в том, что мой второй мьютекс создавался неправильно. Я не знаю, что с ним не так, поэтому я просто использую первый мьютекс для всех потоков. Есть еще кое-что, что я сделал, чтобы заставить его работать, поэтому я обновлю свой псевдокод, чтобы отразить это позже, когда у меня будет минута.

Ответы [ 3 ]

1 голос
/ 02 декабря 2009

Если вы используете какой-либо тип очереди для Data, вы сможете полностью удалить «пустые» семафоры, если только вы не пытаетесь навязать условие, что каждая глубина очереди Data строго равна 0 или 1 Если вы используете локальную переменную в thread2, вы можете уменьшить размер критической секции.

Код становится примерно таким:

thread1() {
    //Wait for data to put in the queue (i.e. a blocking socket read)
    lock(data1_mutex);
    data1.push(someData);
    unlock(data1_mutex);
    post(data1_fill);
}

thread2() {
    DataType dataElement;
    wait(data1_fill);
    lock(data1_mutex);
    dataElement = data1.pop();
    unlock(data1_mutex);

    lock(data2_mutex);
    data2.push(dataElement);
    unlock(data2_mutex);
    post(data2_fill);
}

thread3() {
    DataType dataElement;
    wait(data2_fill);
    lock(data2_mutex);
    dataElement = data2.pop();
    unlock(data2_mutex);
    //do something with dataElement here
}
0 голосов
/ 11 сентября 2009

Что сказал Вранг-Вранг, и постарайтесь не удерживать блокировку для data_1, пока вы ожидаете data_2_empty. Этого можно добиться, сохранив альтернативный буфер для data_1 и data_2, который вы меняете. Thread_2 обменивает данные_1 при обработке их в data_2, thread_3 обменивает данные_2 при их обработке. Ваш текущий псевдокод позволит потоку 1 и потоку 3 работать одновременно, но не позволит потоку 2 выполняться одновременно с любым другим.

0 голосов
/ 11 сентября 2009

Убедитесь, что вы публикуете data1_empty и data2_empty изначально.

...