2016-11-15 3 views
3

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

Вот картина:

08 
    06 07 
03 04 05 
    01 02 
    00 

Thread #08 cannot join the diamond until threads #06 and #07 are both in position. 
Thread #07 cannot join until threads #04 and #05 are both in position. 
Thread #06 cannot join until threads #03 and #04 are both in position. and so on... 

До сих пор мое мышление привело к следующему алгоритму: уродливой

if (me==0) { 
     wait_sem (tCount[1]) ; 
     wait_sem (tCount[2]) ; 
     signal_sem (tCount[0]) ; 
    } 
    if (me==1) { 
     wait_sem (tCount[3]) ; 
     wait_sem (tCount[4]) ; 
    } 
    if (me==2) { 
     wait_sem (tCount[4]) ; 
     wait_sem (tCount[5]) ; 
    } 
    if (me==3) { 
     wait_sem (tCount[6]) ; 
    } 
    if (me==4) { 
     wait_sem (tCount[6]) ; 
     wait_sem (tCount[7]) ; 
    } 
    if (me==5) { 
     wait_sem (tCount[7]) ; 
    } 
    if (me==6) { 
     wait_sem (tCount[8]) ; 
    } 
    if (me==7) { 
     wait_sem (tCount[8]) ; 
    } 

Есть ли уборщик способ сделать это? Я слышал switch, но я никогда не использовал его раньше, поэтому, если кто-нибудь предложит его, пожалуйста, предоставьте мне объяснение и/или пример. Большое спасибо за все входные данные.

ответ

3

Давайте просто возьмем очень простой подход, где вы храните свои семафоры в глобальном массиве (или просто просто доступны для ваших потоков). Вы можете настроить список зависимостей, как это:

std::vector<std::vector<int>> thread_depends = { 
    { },  // 0 
    { 0 }, // 1 
    { 0 }, // 2 
    { 1 }, // 3 
    { 1, 2 }, // 4 
    { 2 }, // 5 
    { 3, 4 }, // 6 
    { 4, 5 }, // 7 
    { 6, 7 }, // 8 
}; 

Теперь каждый поток просто нужно ждать все в thread_depends[me]:

const auto & dep = thread_depends[me]; 
std::for_each(dep.begin(), dep.end(), [&tCount](int who){ wait_sem(tCount[who]); }); 
signal_sem(tCount[me]); 

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

+1

Быстро вопрос, включил бы я этот код в функцию, связанную с алгоритмом, или должен ли я поместить часть ее во всемирный доступ? – Junikin

+0

Трудно дать быстрый ответ на это. – paddy

+0

Хорошо, я понимаю. Я немного поиграю с этим. Спасибо за тонну – Junikin

1

Это решение только для того, чтобы показать, как это можно сделать с футляром, есть более эффективные реализации для этой проблемы!

Коммутатор лучше, чем if/else, потому что он работает как скачок, когда если вам нужно будет проверить все условия до его удовлетворения (if0, if1, if2 ...), то переключатель будет непосредственно в нужном случае.

switch(me) 
{ 
    case 0: 
     wait_sem(tCount[1]); 
     wait_sem(tCount[2]); 
     signal_sem(tCount[me]); 
     break; 
    case 1: 
     wait_sem(tCount[3]) ; 
     wait_sem(tCount[4]) ; 
     signal_sem(tCount[me]); 
     break; 
    case 2: 
     wait_sem(tCount[4]); 
     wait_sem(tCount[5]); 
     signal_sem(tCount[me]); 
     break; 
    case 3: 
     wait_sem(tCount[6]); 
     signal_sem(tCount[me]); 
     break; 
    case 4: 
     wait_sem(tCount[6]); 
     wait_sem(tCount[7]); 
     signal_sem(tCount[me]); 
     break; 
    case 5: 
     wait_sem(tCount[7]); 
     signal_sem(tCount[me]); 
     break; 
    case 6: 
     wait_sem(tCount[8]); 
     signal_sem(tCount[me]); 
     break; 
    case 7: 
     wait_sem(tCount[8]); 
     signal_sem(tCount[me]); 
     break; 
    case 8: 
     signal_sem(tCount[me]); 
     break; 
}