Информация об изменениях

Сообщение 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>        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>
WH>        private volatile int version;
WH>        private volatile bool isWriterInProgress;
WH>


Да, в дотнете volatile означает барьеры памяти. Думал, как в плюсах это является инструкциями только компилятору.
Барьер не полный, в случае с дотнетом:

Термин volatile read означает чтение памяти в сочетании с созданием accure fence.
Accure fence гарантирует что инструкции, стоящие после барьера, не будут перемещены в позицию до барьера.

Обратное гарантируется Release fence, т.е. volatile write.

Посмотрел еще раз внимательнее на чтение:
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 будут еще валидными.