2009-09-10 3 views
0

Я пытаюсь создать проблему с несколькими производителями/потребителями на 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 будут заполняться, но thread2 будет блокироваться и не запускаться. Что-то не так с моей реализацией?

EDIT # 1

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

ответ

0

Обязательно отправьте сообщение data1_empty и data2_empty.

+0

ли вы имеете в виду, прежде чем нити прядут? – Nippysaurus

+0

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

+0

На данный момент у меня нет идеала или отладчика. Я пробовал отправлять сообщения для обоих семафоров, прежде чем откручивать потоки, но это приводит к тому, что data1 устанавливает больше значений, чем у него есть пространство, поэтому я не думаю, что это решение? – Nippysaurus

0

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

1

Если вы используете какой-либо тип очередей для 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

Если .pop() создает копию, то thread3 может разблокировать (data2_mutex) перед использованием dataElement. Если это по ref, то thread2 не может разблокировать data1_mutex, пока не скопирует dataElement в data2. (push и pop не могут оба быть ref, я думаю.) –