![]() |
|
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]()
|
|
| Alca |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3993 Регистрация: 14.6.2006 Репутация: 5 Всего: 50 |
InterlockedIncrement vs. CriticalSection.
Что лучше использовать с точки зрения производительности? И почему? |
|||
|
||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
Если речь о синхронизации объектов, то главное различие между взаимоблокировками и критическими секциями заключается в способе ожидания сигнального состояния объекта: блокировки выполняются в пользовательском режиме, а секции - и в пользовательском, и в режиме ядра.
что из этого следует? если взаимоблокировки используются для долгосрочного ожидания события, то цикл этого ожидания будет забивать загрузку ЦП по полной, что можно будет наблюдать в диспетчере задач. крит. секции же в таких случаях используют объекты синхронизации, чтобы "погрузиться в сон" до момента разблокировки объекта, что не влечет за собой загрузку ЦП как в случае с взаимоблокировками. в каких случаях следует использовать взаимоблокировки? Когда время ожидания разблокировки незначительно, т.е. по сути, когда можно пренебречь временем исполнения эксклюзивной части кода. Если речь об атомарном управлении синхронными счетчиками (x++, x--, x+=y, x-=y, и т.п.), то смысла заводить крит секции тут нет, поскольку время выполнения этих операций намного меньше, чем время управления секцией, поэтому прямые вызовы InterlockedIncrement, InterlockedDecrement, InterlockedExchangeAdd, и т.п. будут наиболее эффективны. -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Lazin |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
Alca, как можно сравнивать интерлоки и крит. секции, первые нужны для выполнения атомарных операци, а вторые для синхронизации.
критические секции нужны для того, что-бы какой-либо ресурс использовался не более чем одним потоком, например
в случае если ф-я initialize_pointer будет вызваться более чем одним потоком может произойти утечка памяти, например поток А проверит указатель pointer, обнаружит что он равен 0, в это время его прервет планировщик задач, и передаст управление потоку Б, который то-же проверит указатель и обнаружит что он равен нулю, потом поток Б создаст объект MyObject и запишет его адрес в указатель, потом планировщик опять передаст управление потоку А, который уже "знает" что указатель равен нулю и поэтому он тоже создаст объект и перезапишет адрес хранящийся в указателе адресом нового объекта. В результате объект будет проинициализирован дважды, это частный случай такого бага как race condinion. Что-бы этого избежать нужно защитить этот участок кода критической секцией
у этого кода есть 2 слабых места(и вообще он ужасен), первое - безопастность с точки зрения исключений, если конструктор MyObject бросит исключение, функция LeaveCriticalSection не будет вызвана, а это приведет к взаимной блокировке (deadlock) при следующем вызове initialize_pointer, эта проблема легко решается с помощью идиомы RAII. второе - время жизни указателя и критической секции не совпадают, если вызвать initialize_pointer до вызова InitializeCriticalSection то произойдет ошибка времени выполнения, эта проблема легко решается заворачиванием критической секции в класс и ее инициализацией в конструкторе класса, впрочем я отвлекся... У атомарных операций другое предназначение, с их помощью к примеру можно состряпать свой примитив синхронизации, но нельзя ничего синхронизировать. Если два потока используют общую переменную, то, если один из потоков просто ее изменит, другой поток (если он выполняется на другом процессоре со своим кэшем) этого не увидит, плюс, компилятор может оптимизировать код и значение переменной не будет меняться так как вы того ожидаете. Что-бы этого не происходило, нужно использовать Interlocked функции, если переменная была изменена этой функцией, то другой поток, на другом процессоре сразу сможет ее прочитать, так-же это изменение будет атомарным. Вот пример использования функции InterlockedCompareExchangePointer, эта функция сравнивает 2 указателя и если они равны, записывает в один из них значение третьего указателя. Это можно использовать например для создания очереди, операции push и pop которой можно выполнять параллельно из нескольких потоков, я же покажу как сделать буфер, в который можно записывать данные из нескольких потоков параллельно. Буфер будет состоять из массива buffer (lol) и указателя на конец использованой части буфера end. Что-бы записать что-нибудь в буфер, поток сначала должен изменить указатель end, увеличить его значение, а потом записать туда данные (начиная со старого значения end и заканчивая новым)
Эту функцию можно вызывать из разных потоков, несмотря на то, что там нет ни критических секций ни мьютексов. зы Обычно гнаться за параллельностью выполнения не стоит, как правило достаточно написать потоко-безопасный код, а для этого хватает и критических секций, ну а если где-то нужно использовать на полную возможности многопроцессорной системы, то можно и поизвращаться с Interlocked функциями и еще много с чем Это сообщение отредактировал(а) Lazin - 30.9.2008, 08:33 |
||||||
|
|||||||
| GremlinProg |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
сравнивать их можно хотя бы потому, что первые являются составной частью вторых (я уже писал, на чем основана работа спин-счетчиков, см. соседние темы) -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
| Lazin |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3820 Регистрация: 11.12.2006 Где: paranoid oil empi re Репутация: 8 Всего: 154 |
(upd)
написал небольшой тестик, оно работает
|
|||
|
||||
| Alca |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3993 Регистрация: 14.6.2006 Репутация: 5 Всего: 50 |
СИНХРОНИЗАЦИЯ
Синхронизация потоков в пользовательском режиме Это сообщение отредактировал(а) Alca - 1.10.2008, 13:03 |
|||
|
||||
![]()
|
| Правила форума "C/C++: Системное программирование и WinAPI" | |
|
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |