Re[3]: Реализация критической секции на Interlocked.Exchange
От: nikov США http://www.linkedin.com/in/nikov
Дата: 19.06.08 09:51
Оценка:
Здравствуйте, С. Ю. Губанов, Вы писали:

СЮГ>1) В языке C# есть такое правило, что если функция объявлена так: void F (ref int x) то фактический параметр x не может быть volatile.


Кстати, Вы не знаете, какое обоснование для этого правила?
Re[3]: Реализация критической секции на Interlocked.Exchange
От: remark Россия http://www.1024cores.net/
Дата: 19.06.08 10:13
Оценка:
Здравствуйте, С. Ю. Губанов, Вы писали:

СЮГ>Здравствуйте, remark, Вы писали:


R>>Если flag объявлен как volatile, то да, если нет — то нет.


СЮГ>А Вы вообще как, знаете что такое язык C#? И что означает слово volatile в этом языке? Вы его с Си или с Си++ не перепутали случайно? Пожалуй, перепутали.


СЮГ>Напоминаю:


СЮГ>1) В языке C# есть такое правило, что если функция объявлена так: void F (ref int x) то фактический параметр x не может быть volatile.


СЮГ>2) int System.Threading.Interlocked.Exchange(ref int location1, int value)



Нет, не перепутал.
ECMA-335 12.6.7

A volatile write has “release semantics” meaning that the write is guaranteed to happen after any memory references prior to the write instruction in the CIL instruction sequence.


Кстати, из вышеуказанных 2 утверждений не следует, что flag объявлен как volatile. Но если всё-таки объявлен, то замечательно, пример рабочий.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[14]: Реализация критической секции на Interlocked.Exchang
От: remark Россия http://www.1024cores.net/
Дата: 19.06.08 10:15
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, remark, Вы писали:



R>>При чтении нужны оба барьера. Барьеры — это всегда игра для двух (потоков). Если барьеры выполняет только один поток, то эффекта от них не будет.


V>Ну дык, пишущий делает барьер до и после записи, а все читающие — только перед чтением, я про экономию одного барьера говорил.


Сколькими барьерами в данном случае синхронизируется передача владения над защищенными данными при выходе читающего потока и входе пишущего?


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[13]: Реализация критической секции на Interlocked.Exchang
От: remark Россия http://www.1024cores.net/
Дата: 19.06.08 10:18
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Желательно также отработать барьер и после этого — чтобы не тянуть с записью нуля в ячейку спинлока, задерживая тем самым других.


R>>Барьеры никак не влияют на задержку. Если бы было какое-то средство для ускорения работы с памятью, поверь мне, оно было бы просто включено всегда по-умолчанию.


N>Это ты за слово "тянуть" зацепился?) Я имел в виду, чтобы запись нуля в ячейку не была раньше, чем запись тех данных, которые должны стать всем видимы до того, как лок освободится.


Барьер после записи тут никак не поможет. Release-барьер всегда делается перед синхронизируещей записью (или вместе, если архитектура совмещает обращения к памяти с барьерами), но не после.

R>>Хотя барьер после освобождения критической секции тоже иногда ставится. Но это уже имеет отношение к fairness, и вообще очень спорный подход для общего случая.


N>Угу, потому и только "желательно".


Моё личное мнение, он там как раз *не* желателен, хотя поставить можно.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Реализация критической секции на Interlocked.Exchange
От: С. Ю. Губанов Россия http://SergeyGubanov.narod.ru/
Дата: 19.06.08 10:24
Оценка:
Здравствуйте, remark, Вы писали:

R>Кстати, из вышеуказанных 2 утверждений не следует, что flag объявлен как volatile.


В C# целочисленная переменная flag не может быть объявлена как volatile по правилам языка, так как если её объявить как volatile, то её нельзя будет передать по ссылке. А внутрь функций семейства System.Threading.Interlocked.*** изменяемая переменная должна быть передана как раз по ссылке, то есть она не может быть "волатильной". Короче, любой кто предлагает объявить в C# "интерлочный" флаг "волатильным", просто никогда сам не пробовал этого сделать в C#, а думает что это правильно по аналогии с какими-то другими языками программирования, например Си/Си++, но в C# это не так.
Re[4]: Реализация критической секции на Interlocked.Exchange
От: С. Ю. Губанов Россия http://SergeyGubanov.narod.ru/
Дата: 19.06.08 10:26
Оценка:
Здравствуйте, nikov, Вы писали:

N>Кстати, Вы не знаете, какое обоснование для этого правила?


Не знаю.
Re[5]: Реализация критической секции на Interlocked.Exchange
От: CreatorCray  
Дата: 19.06.08 10:28
Оценка:
Здравствуйте, С. Ю. Губанов, Вы писали:

СЮГ>если её объявить как volatile, то её нельзя будет передать по ссылке. А внутрь функций семейства System.Threading.Interlocked.*** изменяемая переменная должна быть передана как раз по ссылке, то есть она не может быть "волатильной".

Кстати и правда интересно — а почему запретили то передачу volatile по ссылке?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Реализация критической секции на Interlocked.Exchange
От: Sergey Россия  
Дата: 19.06.08 10:31
Оценка:
С. Ю. Губанов пишет:

> В C# целочисленная переменная flag не может быть объявлена как volatile

> по правилам языка, так как если её объявить как volatile, то её нельзя
> будет передать по ссылке. А внутрь функций семейства
> System.Threading.Interlocked.*** изменяемая переменная должна быть
> передана как раз по ссылке, то есть она не может быть "волатильной".
> Короче, любой кто предлагает объявить в C# "интерлочный" флаг
> "волатильным", просто никогда сам не пробовал этого сделать в C#, а
> думает что это правильно по аналогии с какими-то другими языками
> программирования, например Си/Си++, но в C# это не так.

А кто пишет что "думает что это правильно по аналогии с какими-то
другими языками программирования, например Си/Си++", не знает С++
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[5]: Реализация критической секции на Interlocked.Exchange
От: remark Россия http://www.1024cores.net/
Дата: 19.06.08 11:04
Оценка: 6 (1)
Здравствуйте, С. Ю. Губанов, Вы писали:

СЮГ>Здравствуйте, remark, Вы писали:


R>>Кстати, из вышеуказанных 2 утверждений не следует, что flag объявлен как volatile.


СЮГ>В C# целочисленная переменная flag не может быть объявлена как volatile по правилам языка, так как если её объявить как volatile, то её нельзя будет передать по ссылке. А внутрь функций семейства System.Threading.Interlocked.*** изменяемая переменная должна быть передана как раз по ссылке, то есть она не может быть "волатильной". Короче, любой кто предлагает объявить в C# "интерлочный" флаг "волатильным", просто никогда сам не пробовал этого сделать в C#, а думает что это правильно по аналогии с какими-то другими языками программирования, например Си/Си++, но в C# это не так.



Ладно, уговорил, больше не буду отвечать на вопросы по C#.
Напоследок напишу, что надо так (это проверил — компилируется и работает):
int main(array<System::String^>^)
{
    int flag = 0;
    System::Threading::Interlocked::Exchange(flag, 1);
    System::Threading::Thread::VolatileWrite(flag, 0);
}




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Реализация критической секции на Interlocked.Exchange
От: С. Ю. Губанов Россия http://SergeyGubanov.narod.ru/
Дата: 19.06.08 12:08
Оценка:
Здравствуйте, remark, Вы писали:

R>Напоследок напишу, что надо так (это проверил — компилируется и работает):

R>
R>int main(array<System::String^>^)
R>{
R>    int flag = 0;
R>    System::Threading::Interlocked::Exchange(flag, 1);
R>    System::Threading::Thread::VolatileWrite(flag, 0);
R>}
R>


Спасибо за ещё один способ. Я его не знал.

Сейчас проверил скорость работы своей системы (которую я в общих чертах описал там: http://www.rsdn.ru/forum/message/2993169.1.aspx
Автор: С. Ю. Губанов
Дата: 19.06.08
) в зависимости от завершителя критической секции доступа к очереди задач.

Первое место занимает самый тупой завершитель:
flag = 0;
16.8 миллионов простых задач в секунду.

На втором месте завершитель:
System.Threading.Interlocked.Exchange(ref flag, 0);
15.5 миллионов простых задач в секунду.

И, наконец, на третьем месте завершитель:
System.Threading.Thread.VolatileWrite(ref flag, 0);
12.5 миллионов простых задач в секунду.

То есть Thread.VolatileWrite по непонятным мне причинам ощутимо медленее чем Interlocked.Exchange.
Re[6]: итог
От: С. Ю. Губанов Россия http://SergeyGubanov.narod.ru/
Дата: 19.06.08 12:34
Оценка:
СЮГ> Большое спасибо, это очень важно, а я об этом позабыл. Надо будет принять меры.

Наверное так сойдёт:
            public static void Enter ()
            {
                int t = 0;
                while (System.Threading.Interlocked.Exchange(ref state, 1) != 0)
                {
                    System.Threading.Thread.Sleep(t / 10);
                    t++;
                }
            }
Re[7]: итог
От: С. Ю. Губанов Россия http://SergeyGubanov.narod.ru/
Дата: 19.06.08 12:38
Оценка:
СЮГ>Наверное так сойдёт:

Чуть модернизировал:
            public static void Enter ()
            {
                int t = 0;
                while (System.Threading.Interlocked.Exchange(ref state, 1) != 0)
                {
                    System.Threading.Thread.Sleep(t++ >> 4);
                }
            }
Re[15]: Реализация критической секции на Interlocked.Exchang
От: vdimas Россия  
Дата: 24.06.08 07:39
Оценка:
Здравствуйте, remark, Вы писали:

R>Сколькими барьерами в данном случае синхронизируется передача владения над защищенными данными при выходе читающего потока и входе пишущего?


Одним, в случае передачи от читателя к писателю, и двумя при передаче от писателя к читателю.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re: Реализация критической секции на Interlocked.Exchange
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 24.06.08 08:18
Оценка: 9 (1)
Здравствуйте, SergeyGubanov, Вы писали:

SG>Реализация критической секции на Interlocked.Exchange


SG>Объясните пожалуйста, а то никак не могу врубиться, почему ежели я реализую критическую секцию используя атомарную операцию обмена, то MSDN рекомендует писать так:


Статья как раз про это:

The main purpose of this is to announce “availability” of the locks to other processors. More specifically, it ensures that before the current processor is able to turn around and reacquire the lock in its own private cache, that other processors at least have the opportunity to see the write.

http://www.smalltalk.ru << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[12]: Реализация критической секции на Interlocked.Exchang
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 27.06.08 08:16
Оценка:
Здравствуйте, remark, Вы писали:

R>Здравствуйте, netch80, Вы писали:


N>>Большинству программистов вопрос барьеров _пока_ не важен, потому что в x86 форсированная сериализация операций чтения и записи (то есть защищаемые данные гарантированно запишутся в память раньше, чем 0 в спинлок). Но Intel обещает это скоро отключить.


R>А откуда дровишки? Можно какие-нибудь ссылки?

R>Они ж вроде как только недавно как раз задокументировали свою модель памяти, и там написано, что load имеет семантику acquire, а store — release.

Вероятно, мои данные устарели — они это обещали года три назад. А что значит "имеет семантику acquire"? И где про это почитать?
The God is real, unless declared integer.
Re[13]: Реализация критической секции на Interlocked.Exchang
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 27.06.08 08:28
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Большинству программистов вопрос барьеров _пока_ не важен, потому что в x86 форсированная сериализация операций чтения и записи (то есть защищаемые данные гарантированно запишутся в память раньше, чем 0 в спинлок). Но Intel обещает это скоро отключить.


R>>А откуда дровишки? Можно какие-нибудь ссылки?

R>>Они ж вроде как только недавно как раз задокументировали свою модель памяти, и там написано, что load имеет семантику acquire, а store — release.

N>Вероятно, мои данные устарели — они это обещали года три назад.


Примерно тогда вводились команды RFENCE, SFENCE, MFENCE.

N> А что значит "имеет семантику acquire"? И где про это почитать?


Уточняю вопрос — чем это отличается по результату (не по определению) от простого упорядочения операций? Описание такого рода:

In between those extremes are a lot of different possibilities. Those possibilities are explained in terms of acquire and release semantics:



* A normal load or store can be freely reordered with respect to other normal load or store operations.
* A load with acquire semantics creates a downwards fence. This means that normal loads and stores can be moved down past the load.acquire, but nothing can be moved to above the load.acquire.
* A store with release semantics creates an upwards fence. This means that normal loads and stores can be moved above the store.release, but nothing can be moved to below the store.release.
* A full fence is effectively an upwards and downwards fence. Nothing can move in either direction across a full fence.

(источник: http://blogs.msdn.com/cbrumme/archive/2003/05/17/51445.aspx)

даёт, если мы считаем, что все load автоматически acquire, а store — release, что переупорядочение вообще между ними невозможно (или последствия не уточнены, потому что везде говорится про normal loads and stores).

Далее там же видим:

In terms of the above, the memory model for X86 can be described as:



1. All stores are actually store.release.
2. All loads are normal loads.
3. Any use of the LOCK prefix (e.g. ‘LOCK CMPXCHG’ or ‘LOCK INC’) creates a full fence.


что расходится с Вашим описанием (в пункте 2).
The God is real, unless declared integer.
Re[8]: итог
От: merk Россия  
Дата: 30.06.08 00:22
Оценка:
Здравствуйте, С. Ю. Губанов, Вы писали:

СЮГ>>Наверное так сойдёт:


СЮГ>Чуть модернизировал:

СЮГ>
СЮГ>            public static void Enter ()
СЮГ>            {
СЮГ>                int t = 0;
СЮГ>                while (System.Threading.Interlocked.Exchange(ref state, 1) != 0)
СЮГ>                {
СЮГ>                    System.Threading.Thread.Sleep(t++ >> 4);
СЮГ>                }
СЮГ>            }
СЮГ>


для скорости не слип нужно делать, а yield — переключение тредов.
не знаю точно, но похоже в .NET это sleep(0). смотрел по диагонали, yield там вроде нет.
но семантика sleep(0) как раз нужная.
Re[16]: Реализация критической секции на Interlocked.Exchang
От: remark Россия http://www.1024cores.net/
Дата: 07.07.08 20:00
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Здравствуйте, remark, Вы писали:


R>>Сколькими барьерами в данном случае синхронизируется передача владения над защищенными данными при выходе читающего потока и входе пишущего?


V>Одним, в случае передачи от читателя к писателю, и двумя при передаче от писателя к читателю.


В случае передачи от читателя к писателю — проблема, т.к. одним барьером нельзя сделать синхронизацию. Т.е. грубо говоря, при передаче владения от читателя к писателю выполнение читателей и писателя "наложится во времени" с непредсказуемыми результатами.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[14]: Реализация критической секции на Interlocked.Exchang
От: remark Россия http://www.1024cores.net/
Дата: 07.07.08 20:24
Оценка: 5 (1)
Здравствуйте, netch80, Вы писали:

N>>>>Большинству программистов вопрос барьеров _пока_ не важен, потому что в x86 форсированная сериализация операций чтения и записи (то есть защищаемые данные гарантированно запишутся в память раньше, чем 0 в спинлок). Но Intel обещает это скоро отключить.


R>>>А откуда дровишки? Можно какие-нибудь ссылки?

R>>>Они ж вроде как только недавно как раз задокументировали свою модель памяти, и там написано, что load имеет семантику acquire, а store — release.

N>>Вероятно, мои данные устарели — они это обещали года три назад.


N>Примерно тогда вводились команды RFENCE, SFENCE, MFENCE.


Аааа... Вроде я слышал что-то такое, что Intel какое-то время назад опубликовал некую модель памяти x86-SPO, и она действительно была более слабая, чем текущая. Но насколько я знаю это дело сейчас заглохло, и никаких процессов, реализующих x86-SPO не было. Вот тут вроде есть упоминание x86-SPO:
http://gee.cs.oswego.edu/dl/jmm/cookbook.html


N>> А что значит "имеет семантику acquire"? И где про это почитать?


N>Уточняю вопрос — чем это отличается по результату (не по определению) от простого упорядочения операций? Описание такого рода:


N>

N>In between those extremes are a lot of different possibilities. Those possibilities are explained in terms of acquire and release semantics:
N> * A normal load or store can be freely reordered with respect to other normal load or store operations.
N> * A load with acquire semantics creates a downwards fence. This means that normal loads and stores can be moved down past the load.acquire, but nothing can be moved to above the load.acquire.
N> * A store with release semantics creates an upwards fence. This means that normal loads and stores can be moved above the store.release, but nothing can be moved to below the store.release.
N> * A full fence is effectively an upwards and downwards fence. Nothing can move in either direction across a full fence.

(источник: http://blogs.msdn.com/cbrumme/archive/2003/05/17/51445.aspx)


N>даёт, если мы считаем, что все load автоматически acquire, а store — release, что переупорядочение вообще между ними невозможно


Из этого не следует, что переупорядочивания между ними не возможны. Например, в таком примере:
store_release(x, 1);
store_release(y, 1);

или в таком:
r = load_acquire(x);
store_release(y, 1);

переупорядочивая не возможны. А вот в таком:
store_release(y, 1);
r = load_acquire(x);

возможны. Например, процессор может выполнить (и скорее всего так и сделает) это как:
r = load_acquire(x);
store_release(y, 1);

Заметь, через acquire ничего не прошло вврех, а через release ничего не прошло вниз.

Это, кстати, занятное отличие модели памяти Java от С# (CLI). CLI позволяет делать переупорядочивание, как я показал, а Java — нет.


N>Далее там же видим:


N>

N>In terms of the above, the memory model for X86 can be described as:
N> 1. All stores are actually store.release.
N> 2. All loads are normal loads.
N> 3. Any use of the LOCK prefix (e.g. ‘LOCK CMPXCHG’ or ‘LOCK INC’) creates a full fence.


N>что расходится с Вашим описанием (в пункте 2).


К сожалению сейчас ссылка не открывается, но судя по всему этот материал датирован 2003 годом. Я думаю проблема в этом. До недавнего времени Intel вообще официально не описывал модель памяти x86. Поэтому всё это было в виде "из уст в уста".

Вот официальная модель памяти Intel x86 (датирована 08-2007):
http://www.intel.com/products/processor/manuals/318147.pdf

В качестве общего материала ещё можно посмотреть Memory Ordering in Modern Microprocessors:
http://www.linuxjournal.com/article/8211
http://www.linuxjournal.com/article/8212
(там хорошее введение в вопрос, но датирована она 2005, и там тоже говорится, что x86 может переупорядочивать загрузки)

Ещё есть The JSR-133 Cookbook for Compiler Writers:
http://gee.cs.oswego.edu/dl/jmm/cookbook.html
(это уже 2008 год, и там корректно указана модель памяти x86)


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[17]: Реализация критической секции на Interlocked.Exchang
От: vdimas Россия  
Дата: 10.07.08 17:41
Оценка:
Здравствуйте, remark, Вы писали:


R>В случае передачи от читателя к писателю — проблема, т.к. одним барьером нельзя сделать синхронизацию. Т.е. грубо говоря, при передаче владения от читателя к писателю выполнение читателей и писателя "наложится во времени" с непредсказуемыми результатами.


Там было не про передачу управления, а о доступе к атомарной ячейке памяти (в которой указатель, например). Писателю нужно сделать 2 барьера — до и после модификации этой ячейки, читателю — только до. Если в момент чтения читателем в многопроцессорной системе писатель тоже можифицирует ячейку — фиг с ним, в близком времени эта модификация видна будет только после барьера этого писателя.
... << RSDN@Home 1.2.0 alpha rev. 786>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.