Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > барьер в многопоточном приложении


Автор: ksili 5.5.2009, 13:14
У меня основной поток запускает несколько дочерних и должен стоять пока они все не завершатся. Делаю так:

в основном потоке
Код

volatile long wait1 = 0; // глобальная переменная


        for(i = 0; i < n; i++)    
        {
            InterlockedIncrement(&wait1);
            (HANDLE)_beginthreadex(NULL, 0, _solveProc16, &args[i], 0, NULL);    
        }

    // wait all threads
    while(wait1 > 0)    
        SwitchToThread();



в функции потока:
Код

unsigned  __stdcall _solveProc16(void *pArgs)
{
....

    InterlockedDecrement(&wait1);
    return 16;
}

Я не большой знаток, кажется такой while является спин-блокировкой... 

Нет ли здесь каких-нибудь граблей? Дело в том, что в дебаге и в релизе программа работает по-разному, и также результат различается, если запускать из-под IDE и просто екзешник.

Автор: Alek86 5.5.2009, 13:19
может лучше заюзать WaitForMultipleObjects?
или в boost.thread где-то были группы потоков

Автор: Fazil6 5.5.2009, 13:26

Код


HANDLE h[5];
for(i = 0; i < 5; i++)    
        {
             h[i] = (HANDLE)_beginthreadex(NULL, 0, _solveProc16, &args[i], 0, NULL);    
        }
    
// wait all threads
    WaitForMultipleObjects(5, h, true, INFINITE);

Автор: ksili 5.5.2009, 13:33
Сейчас попробую переписать на WaitForMultipleObjects, но всё же хотелось разобраться и в минусах приведённого кода т.к. у WaitForMultipleObjects количество ожидаемых объектов довольно ограничено и в какой-нибудь задаче может его и не хватить.

Автор: Lazin 5.5.2009, 13:43
Цитата(ksili @  5.5.2009,  13:33 Найти цитируемый пост)
Сейчас попробую переписать на WaitForMultipleObjects, но всё же хотелось разобраться и в минусах приведённого кода т.к. у WaitForMultipleObjects количество ожидаемых объектов довольно ограничено и в какой-нибудь задаче может его и не хватить. 

а зачем тебе больше 64х потоков, если их больше, то можно ждать сначала первые 64, потом - следующие 64, итд, можно еще сделать так:

Код

boost::thread_group threads;
for (int i = 0; i < boost::thread::hardware_concurrency(); ++i)
    threads.create(&_solveProc16);

....

threads.join_all();

Автор: J0ker 5.5.2009, 16:50
Lazin, +1

Цитата(ksili @  5.5.2009,  13:14 Найти цитируемый пост)
Я не большой знаток, кажется такой while является спин-блокировкой... 

не является по причине SwitchToThread
но не кошерно - в таких случаях положено использовать механизмы с ожиданием

Автор: Lazin 5.5.2009, 17:05
Цитата(ksili @  5.5.2009,  13:14 Найти цитируемый пост)
    // wait all threads
    while(wait1 > 0)    
        SwitchToThread();

если и использовать этот код, то лучше сделать так:

Код

while( InterlockedCompareExchange(&wait1, 0, 0) != 0 )    
        SwitchToThread();


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

Добавлено через 4 минуты и 48 секунд
но это может произойти только на многопроцессорной машине

Автор: J0ker 5.5.2009, 17:46
Цитата(Lazin @  5.5.2009,  17:05 Найти цитируемый пост)
то лучше сделать так:

+1

Цитата(Lazin @  5.5.2009,  17:05 Найти цитируемый пост)
иначе, может возникнуть задержка между завершением последнего потока и продолжением работы программы

Добавлено через 4 минуты и 48 секунд
но это может произойти только на многопроцессорной машине 

почему? из-за кэша процессора?

Автор: MAKCim 5.5.2009, 17:59
Цитата(Lazin @  5.5.2009,  17:05 Найти цитируемый пост)
иначе, может возникнуть задержка между завершением последнего потока и продолжением работы программы

декрементация может прозойти после выполнения условия в while но до вызова SwithToThread
это классический race

Автор: J0ker 5.5.2009, 18:05
Цитата(MAKCim @  5.5.2009,  17:59 Найти цитируемый пост)
декрементация может прозойти после выполнения условия в while но до вызова SwithToThread
это классический race 

при чем тут race???
ну завершится цикл на следующем слайсе
нет тут никакого "классического race"

Автор: MAKCim 5.5.2009, 18:09
Цитата(J0ker @  5.5.2009,  18:05 Найти цитируемый пост)
при чем тут race???

под race'ом в _конкретном_ случае я понимаю недетерминированность порядка следования сравнения и декрементации
здесь race является безопасным, т. к кроме
Цитата

ну завершится цикл на следующем слайсе

ничего больше произойти не может

Автор: J0ker 5.5.2009, 18:16
Цитата(MAKCim @  5.5.2009,  18:09 Найти цитируемый пост)
ничего больше произойти не может

именно поэтому это не race condition

Автор: Lazin 6.5.2009, 08:02
Цитата(J0ker @  5.5.2009,  17:46 Найти цитируемый пост)
почему? из-за кэша процессора?

ну да, поток, проверяющий значение в цикле while, может не "увидеть" вовремя изменение
если хочешь работать с переменной атомарно, то нужно работать с ней только через Interlocked*** ф-ии, это касается не только записи, но и чтения

Автор: MAKCim 6.5.2009, 08:55
Цитата(Lazin @  6.5.2009,  08:02 Найти цитируемый пост)
если хочешь работать с переменной атомарно, то нужно работать с ней только через Interlocked*** ф-ии, это касается не только записи, но и чтения 


Цитата(ksili @  5.5.2009,  13:14 Найти цитируемый пост)
while(wait1 > 0)

здесь чтение атомарно, если 
sizeof(long) = 4 и x86, x86-64
или
sizeof(long) = 8 и x86-64

кроме того, кэш сдесь не причем
если переменная (строка) будет находится более чем в одном L1 кэше, то любое ее изменение приведет инвалидации ее в других кэшах
все зависит от того, что отработало раньше: чтение или декремент/инкремент
и никакие Interlocked функции тут не помогут

в данном случае кэширования переменной в регистре не будет из-за volatile

Цитата(J0ker @  5.5.2009,  18:16 Найти цитируемый пост)
именно поэтому это не race condition

самый настоящий race

Автор: Lazin 6.5.2009, 10:27
Цитата(MAKCim @  6.5.2009,  08:55 Найти цитируемый пост)
кроме того, кэш сдесь не причем
если переменная (строка) будет находится более чем в одном L1 кэше, то любое ее изменение приведет инвалидации ее в других кэшах


Цитата(MAKCim @  6.5.2009,  08:55 Найти цитируемый пост)
в данном случае кэширования переменной в регистре не будет из-за volatile

действительно, был не прав smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)