OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 19 Март, 2024 10:57

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 29 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 11:16 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Вот, ежели я реализую критическую секцию используя атомарную операцию обмена, то MSDN рекомендует писать что-то вроде следующего:
Код:
if (System.Threading.Interlocked.Exchange(ref flag, 1) == 0)
{
  // ...
  // ...
  // ...
  System.Threading.Interlocked.Exchange(ref flag, 0);
}

А почему бы не написать попроще:
Код:
if (System.Threading.Interlocked.Exchange(ref flag, 1) == 0)
{
  // ...
  // ...
  // ...
  flag = 0;
}

Вроде второй вариант тоже правильный, или нет?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 11:44 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
В данном случае, может быть, и будет работать.

А вообще, если во время записи в переменную кто-то ещё может её читать, то надо использовать Interlocked. Может быть (теоретически, относительно тех. возможности конкр. процессоров не знаю) такая ситуация, что один процессор записал только часть слова, а второй уже полез читать.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 11:54 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Сергей Губанов писал(а):
Вроде второй вариант тоже правильный, или нет?

Ёй! Лучше - не надо! - Неизвестно на какой проц, в недалёком и светлом будущем, это потом нативно скомпилено будет...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 12:09 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Илья Ермаков писал(а):
такая ситуация, что один процессор записал только часть слова, а второй уже полез читать.

Не,... с частями слова - наврядли, но вот на счёт такого - вполне "ох-ох-ох":
Код:
mov eax,0 // или  xor eax,eax
// здесь уходим в другой поток, потом - продолжаем...
mov var,eax

В то время, как System.Threading.Interlocked.Exchange(ref flag, 1) скорее всего подразумевает компиляцию в команду, типа xchg на х86 (или её аналог на других архитектурах), которая в любых условиях и архитектурах выполняется гарантированно атомарно...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 12:22 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Спасибо.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 16 Июнь, 2008 12:45 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Владимир Лось писал(а):
Код:
mov eax,0 // или  xor eax,eax
// здесь уходим в другой поток, потом - продолжаем...
mov var,eax


Не совсем понимаю чем это плохо? Ведь переменной flag всё равно будет присвоен 0, правда не мгновенно, а с небольшой задержкой.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 18 Июнь, 2008 19:31 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
Сергей Губанов писал(а):
Владимир Лось писал(а):
Код:
mov eax,0 // или  xor eax,eax
// здесь уходим в другой поток, потом - продолжаем...
mov var,eax


Не совсем понимаю чем это плохо? Ведь переменной flag всё равно будет присвоен 0, правда не мгновенно, а с небольшой задержкой.

Как-то не кошет...
А если у вас флаг не бинарным будет?... Да ещё и "привязанный" значениями к потокам?... :о)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 09:50 

Зарегистрирован: Понедельник, 28 Ноябрь, 2005 10:28
Сообщения: 1428
Скорее всего flag = 0; будет скомпилировано в
Код:
mov flag, 0
, а System.Threading.Interlocked.Exchange - в вызов InterlockedExchange.
Код:
  push 0
  push flag
  call InterlockedExchange
  ...
InterlockedExchange:
  mov     ecx, [esp+4]
  mov     eax, [esp+8]
  xchg    eax, [ecx]
  ret     8

Особой разницы не вижу


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 12:55 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Я на RSDN спросил:
http://www.rsdn.ru/forum/message/2988602.1.aspx
там сказали, что может случится так, что слишком интеллектуальный процессор с целью оптимизации может поменять порядок выполнения инструкций и код flag = 0 может оказаться выполненым чуть раньше чем надо, но код с "интерлокедом" процессор с другим кодом менять местами не будет.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 13:09 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4625
Откуда: Россия, Орёл
Короче с этими навороченными CISC процессорами программировать приходится с RISC-ом для себя. Как в Си++ -- множество подводных камней. И не знаешь, как себя будет вести завтра новая модель...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 16:39 

Зарегистрирован: Среда, 12 Декабрь, 2007 19:41
Сообщения: 21
Может быть изменен порядок не инструкций (хотя и инструкций тоже может) а непосредственно операций чтения и записи. Причем не только самим CPU, но и продвинутым компилятором.
Конкретно на x86 - операция чтения может быть помещена CPU перед операцией записи, хотя встречена сперва запись. В рамках одного ядра/процессора обеспечивается верный результат, а вот при многоядерности/многопроцессорности уже нет.
Есть понятие такое - барьер (MemoryBarrier в Windows). Через него операции "не проходят". Interlockedxxx уже содержат этот барьер.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 17:22 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Mirage писал(а):
Конкретно на x86 - операция чтения может быть помещена CPU перед операцией записи, хотя встречена сперва запись.

Это хорошо, значит на x86 операция записи flag = 0; выполнится заведомо после фактического выхода из критической секции. Значит можно безбоязнено использовать простую flag = 0; вместо её интерлокед-варианта...

Я на работе уже на три ночи оставлял программу работать с простым flag = 0; она всё ещё и не зависла. Машина: Athlon64 X2.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Четверг, 19 Июнь, 2008 20:25 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4625
Откуда: Россия, Орёл
Сергей Губанов писал(а):
Значит можно безбоязнено использовать простую flag = 0; вместо её интерлокед-варианта...
А смысл? Оптимизация?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Июнь, 2008 09:45 

Зарегистрирован: Среда, 12 Декабрь, 2007 19:41
Сообщения: 21
Сергей Губанов писал(а):
Это хорошо, значит на x86 операция записи flag = 0; выполнится заведомо после фактического выхода из критической секции. Значит можно безбоязнено использовать простую flag = 0; вместо её интерлокед-варианта...


Эт если инструкции из защищенной секции не будут перемещен CPU еще дальше, а он может. Если будут, то секция не будет полностью защищать весь код. Вобщем станут возможны всякие чудеса. И тесты это не выявят, т.к. перемещение инструкций зависит от кода, т.е. тест должен все время менять защищенный код.

Если так важна скорость, то может имеет смысл использовать т.н. lockless синхронизацию. В принципе, как раз это и пытаетесь сделать, т.к. Interlockedxxx обычно тут и используются. Но еще есть ассемблерные инструкции типа cmpxchg, через которые interlockedxxx и работают.
Но тут надо очень хорошо понимать все эти перемещения инструкций, операций чтения/записи и т.п. и знать когда надо ставить барьеры, а когда не надо.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Июнь, 2008 09:55 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Евгений Темиргалеев писал(а):
А смысл? Оптимизация?

Да. Если вместо двух interlocked-операций можно использовать только одну, то будет работать почти в два раза быстрее! Операции семейства Interlocked.*** на многопроцессорной машине выполняются тактов примерно от 20-30 и более в зависимости от типа и количества процессоров (20-30 - это не теоретическое значение, а это я типа померил на Athlon 64 X2). Хотя конечно, на однопроцессорной машине при наличии всего одного потока время выполнения может быть небольшим, затрудняюсь сказать сколько, наверное тактов 2-6. Ежели надо защитить участок кода, который сам выполняется тактов за 5-10, то использование спинлока на interlocked-операциях самое то.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Июнь, 2008 09:59 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 18:55
Сообщения: 2272
Откуда: Россия, Нижний Новгород
Mirage писал(а):
Эт если инструкции из защищенной секции не будут перемещен CPU еще дальше

А если я сделаю присваивание flag = 0 в отдельной процедуре Exit:
Код:
MySpinlockCriticalSection.Enter;
...
a := b;
MySpinlockCriticalSection.Exit;

неужели процессор на столько может обнаглеть, что выполнит сначала MySpinlockCriticalSection.Exit; а потом a := b? Всё-таки вызов процедуры...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 20 Июнь, 2008 10:54 

Зарегистрирован: Среда, 12 Декабрь, 2007 19:41
Сообщения: 21
Сергей Губанов писал(а):
неужели процессор на столько может обнаглеть, что выполнит сначала MySpinlockCriticalSection.Exit; а потом a := b? Всё-таки вызов процедуры...


Вызов процедуры для CPU это не более чем инструкция call. Её тоже наверное может подвинуть. И те, что "в ней", тоже. Насколько я знаю, call барьером не является.
Вот если вызов косвенный, то, опять же если не угадает с предсказанием перехода, то инструкции в процедуре не переместит, т.к. их не будет в конвейере или куда он их там выбирает.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Июнь, 2008 13:02 

Зарегистрирован: Воскресенье, 28 Май, 2006 22:12
Сообщения: 1693
"...а как всё хорошо начиналось! - вызываем в Москву... и как всё закончилось - на конкурс самодеятельности!..."

И вот представьте: это кто понимайт - говорит и обсуждает ( с разумением оп чём ваще речь идёт ), а каково среднестатистическому вчерашнему студенту (да - и не только!)?! : "Фсё зробыв по правилам! - а включашь - фигня получается!" :twisted:


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 22 Июнь, 2008 22:39 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
Владимир Лось писал(а):
И вот представьте: это кто понимайт - говорит и обсуждает ( с разумением оп чём ваще речь идёт ), а каково среднестатистическому вчерашнему студенту (да - и не только!)?! : "Фсё зробыв по правилам! - а включашь - фигня получается!" :twisted:


Студент в любой книжке про многопоточную разработку прочитает про примитивы синхронизации. И будет их использовать. А уж если он захочет свой примитив забабахать, то пусть читает про барьеры, особенности процессоров и т.д.

P.S. Почему нельзя использовать флажки в виде обычный переменных для синхронизации - в приличных книжках тоже пишут. Потому как это частая ошибка у недоучившихся студентов.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 23 Июнь, 2008 06:43 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 9459
Откуда: Россия, Орёл
Так речь не о примитивах синхронизации, а о "соответствии" написанного и сгенерированного кода, которое может получиться... С точки зрения синхронизации первый вариант Сергея вполне верен - если изменение идёт внутри критической секции, значит, его выполняет только один поток. Однако, зная, что всегда тут будут "заподлы", я бы, конечно, так не стал делать, о чём сказал Сергею... А дальше коллеги конкретно объяснили, почему...


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 29 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2024, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB