Почему есть нить.Сон(1) in.NET внутренняя хэш-таблица?


недавно я читал реализацию .NET Hashtable и столкнулся с куском кода, который я не понимаю. Часть кода:

int num3 = 0;
int num4;
do
{
   num4 = this.version;
   bucket = bucketArray[index];
   if (++num3 % 8 == 0)
     Thread.Sleep(1);
}
while (this.isWriterInProgress || num4 != this.version);

весь код находится внутри public virtual object this[object key] of System.Collections.Hashtable (версия mscorlib=4.0.0.0).

вопрос:

в чем причина того Thread.Sleep(1) есть?

3 70

3 ответа:

Sleep (1) является документированным способом в Windows, чтобы дать процессор и позволить другим потокам работать. Вы можете найти этот код в справочном источнике с комментариями:

   // Our memory model guarantee if we pick up the change in bucket from another processor,
   // we will see the 'isWriterProgress' flag to be true or 'version' is changed in the reader.
   //
   int spinCount = 0;
   do {
       // this is violate read, following memory accesses can not be moved ahead of it.
       currentversion = version;
       b = lbuckets[bucketNumber];

       // The contention between reader and writer shouldn't happen frequently.
       // But just in case this will burn CPU, yield the control of CPU if we spinned a few times.
       // 8 is just a random number I pick.
       if( (++spinCount) % 8 == 0 ) {
           Thread.Sleep(1);   // 1 means we are yeilding control to all threads, including low-priority ones.
       }
   } while ( isWriterInProgress || (currentversion != version) );

переменная isWriterInProgress является изменчивым bool. У автора были некоторые проблемы с английским "нарушать чтение" - это "изменчивое чтение". Основная идея заключается в том, чтобы попытаться избежать уступок, переключатели контекста потока очень дороги, с некоторой надеждой на то, что писатель быстро справится. Если это не сработает, то явно уступите, чтобы избежать сжигания процессора. Это, вероятно, было бы написано с помощью Spinlock сегодня, но Hashtable очень старый. Как и предположения о модели памяти.

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

тем не менее, похоже, что он пытается обновить что-то в хэш-таблице, либо в памяти, либо на диске, и делает бесконечный цикл, ожидая его завершения (Как видно, проверяя isWriterInProgress).

Если это одноядерный процессор, он может запускать только один поток за раз. Переход в непрерывный цикл, как это может легко означать другой поток не имеет возможности запустить, но Thread.Sleep(1) дает процессору возможность дать время для писателя. Без ожидания поток записи может никогда не получить шанс запустить и никогда не завершится.

Я не читал источник, но он выглядит как без блокировки параллелизма. Вы пытаетесь читать из хэш-таблицы, но кто-то другой может писать в нее, поэтому вы ждете, пока isWriterInProgress Не задано, и версия, которую вы прочитали, не изменилась.

Это не объясняет, почему, например, мы всегда ждем хотя бы один раз. EDIT: это потому, что мы этого не делаем, спасибо @Maciej за указание на это. Когда нет никаких разногласий, мы приступаем немедленно. Я не знаю, почему 8-это магическое число вместо например 4 или 16, хотя.