Сообщение Re[5]: clr perf problem от 07.07.2015 10:34
Изменено 07.07.2015 11:28 vdimas
Здравствуйте, WolfHound, Вы писали:
M>>>1)Hashtable is thread safe.
V>>Строго говоря — нет.
V>>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
WH>Открываем System.Collections.Hashtable декомпилятором и видим:
WH>
WH>Опять говоришь о том, что не знаешь.
Ошибаешься.
См. Thread.VolatileRead/Thread.VolatileWrite.
Простой volatile не обкладывается барьерами памяти, это лишь инструкция компилятору, но не процессору. Если ты не в курсе, что это означает последние лет 10 для SMP, так спроси, помогу разобраться.
WH>Не надоело позориться?
А, ну-ну. Узнаю старика Крупского ))
Вот это читал?
См. на алгоритм удаления значения:
Объяснения нужны?
M>>>1)Hashtable is thread safe.
V>>Строго говоря — нет.
V>>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
WH>Открываем System.Collections.Hashtable декомпилятором и видим:
WH>
WH> private volatile int version;
WH> private volatile bool isWriterInProgress;
WH>WH>Опять говоришь о том, что не знаешь.
Ошибаешься.
См. Thread.VolatileRead/Thread.VolatileWrite.
Простой volatile не обкладывается барьерами памяти, это лишь инструкция компилятору, но не процессору. Если ты не в курсе, что это означает последние лет 10 для SMP, так спроси, помогу разобраться.
WH>Не надоело позориться?
А, ну-ну. Узнаю старика Крупского ))
Вот это читал?
Что здесь имелось ввиду? Попробуй порассуждать.т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
См. на алгоритм удаления значения:
isWriterInProgress = true;
// Clear hash_coll field, then key, then value
buckets[bn].hash_coll &= unchecked((int)0x80000000);
if (buckets[bn].hash_coll != 0) {
buckets[bn].key = buckets;
}
else {
buckets[bn].key = null;
}
buckets[bn].val = null; // Free object references sooner & simplify ContainsValue.
count--;
UpdateVersion();
isWriterInProgress = false;Объяснения нужны?
Re[5]: clr perf problem
Здравствуйте, WolfHound, Вы писали:
M>>>1)Hashtable is thread safe.
V>>Строго говоря — нет.
V>>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
WH>Открываем System.Collections.Hashtable декомпилятором и видим:
WH>
Да, в дотнете volatile означает барьеры памяти. Думал, как в плюсах это является инструкциями только компилятору.
Барьер не полный, в случае с дотнетом:
Посмотрел еще раз внимательнее на чтение:
Т.е. операция b = lbuckets[bucketNumber] является независимой от обращения к полям isWriterInProgress и currentversion, т.е. может произойти уже после их чтения. Барьер по чтению как раз это разрешает.
После этого while идет проверка на то, что найденный ключ b.key соответствует искомому.
См. на конкурирующий алгоритм удаления значения:
В момент чтения b = lbuckets[bucketNumber] без всяких барьеров можно прочитать в поля bucket значения из памяти в произвольном порядке, например прочитать в b.val null, в то время как b.key и b.hash_coll будут еще валидными.
M>>>1)Hashtable is thread safe.
V>>Строго говоря — нет.
V>>В Hashtable нет ни volatile read/write, ни memory barriers, т.е. вполне возможно зачитка по уже имеющемуся ключу еще не вставленного значения или же наоборот: зачитка ключа от уже удалённого значения.
WH>Открываем System.Collections.Hashtable декомпилятором и видим:
WH>
WH> private volatile int version;
WH> private volatile bool isWriterInProgress;
WH>Да, в дотнете volatile означает барьеры памяти. Думал, как в плюсах это является инструкциями только компилятору.
Барьер не полный, в случае с дотнетом:
Обратное гарантируется Release fence, т.е. volatile write.Термин volatile read означает чтение памяти в сочетании с созданием accure fence.
Accure fence гарантирует что инструкции, стоящие после барьера, не будут перемещены в позицию до барьера.
Посмотрел еще раз внимательнее на чтение:
private bucket[] buckets; // без volatile
...
bucket[] lbuckets = buckets;
...
do
{
int currentversion;
int spinCount = 0;
do {
// this is violate read, following memory accesses can not be moved ahead of it.
currentversion = version;
b = lbuckets[bucketNumber];
...
} while ( isWriterInProgress || (currentversion != version) );Т.е. операция b = lbuckets[bucketNumber] является независимой от обращения к полям isWriterInProgress и currentversion, т.е. может произойти уже после их чтения. Барьер по чтению как раз это разрешает.
После этого while идет проверка на то, что найденный ключ b.key соответствует искомому.
См. на конкурирующий алгоритм удаления значения:
isWriterInProgress = true;
// Clear hash_coll field, then key, then value
buckets[bn].hash_coll &= unchecked((int)0x80000000);
if (buckets[bn].hash_coll != 0) {
buckets[bn].key = buckets;
}
else {
buckets[bn].key = null;
}
buckets[bn].val = null; // Free object references sooner & simplify ContainsValue.
count--;
UpdateVersion();
isWriterInProgress = false;В момент чтения b = lbuckets[bucketNumber] без всяких барьеров можно прочитать в поля bucket значения из памяти в произвольном порядке, например прочитать в b.val null, в то время как b.key и b.hash_coll будут еще валидными.