2013-11-15 3 views
70

Недавно я читал реализацию .NET Hashtable и столкнулся с частью кода, которую я не понимаю. Часть кода:Почему существует Thread.Sleep (1) в .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] из System.Collections.Hashtable (mscorlib Version = 4.0.0.0).

Возникает вопрос:

Что является причиной того, Thread.Sleep(1) там?

+7

Похож на спинвитер перед переключением контекста. То есть он проверяет состояние 8 раз, прежде чем положить поток в режим сна. – Groo

+4

[Аналогичная тема] (http://stackoverflow.com/questions/508208/what-is-the-impact-of-thread-sleep1-in-c); Crux должен позволить ОС планировать другую задачу – Konstantin

ответ

70

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 очень старый. Как и предположения о модели памяти.

+7

Я думал, что «Сон (0)» был рекомендован, если вам нужен только доход. 'Sleep (1)' на самом деле является сном. –

+11

Сон (0) выводится только в том случае, если есть еще один поток, готовый к запуску с более высоким приоритетом. Не намерение здесь. –

+0

Только для потоков с равным приоритетом на самом деле ... что и означает доходность. –

5

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

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

+3

Нет, мы этого не делаем. После '++ num3',' num3' будет 1. Или я серьезно не имею кофеина. –

+0

@MaciejStachowski упс, хороший улов, я неправильно его понял. –

+0

Сон выполняется только после 8 последовательных итераций, в которых выполняется запись, или версия неверна. Предположительно, чтобы дать писателю возможность выполнить свою работу. – dan04

7

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

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

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