K>"Для использования спин-блокировки в критической секции нужно инициализи ровать счетчик циклов, вызвав: K>BOOL InitalizeCriticalSectionAndSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount); K>Как и в InitializeCriticalSection, первый параметр этой функции — адрес структуры критической секции. Но во втором параметре, dwSpinCount, передается число циклов спин-блокировки при попытках получить доступ к ресурсу до перевода потока в состояние ожидания. Этот параметр может принимать значения от 0 до 0x00FFFFFF. Учтите, что на однопроцессорной машине значение параметра dwSpinCount игнорируется и считается равным 0. Дело в том, что применение спин-блокировки в такой системе бессмысленно: поток, владеющий ресурсом, не сможет освободить его, пока другой поток «крутится» в циклах спин-блокировки." K> Не понятно почему на однопроцессорной машине, пока один поток крутиться в цикле, другой не сможет освободить ресурс. Если у нах одиноковый приоритет, то зацикленный поток по окончанию своего кванта прервется и другой поток сможет освободить ресурс(хотя смотря на чем прервался, наверное). При чем здесь кол-во процессоров? Попробую я тоже объяснить своими словами. Цель введения спин-блокировки — увеличить производительность на многопроцессорных машинах. Дело в том, что переход потока в состояние ожидания и следующее за ним переключение контекста между потоками — это довольно длительная операция, сотни, если не тысячи инструкций процессора. В то же время фрагмент кода, защищаемый критической секцией, зачастую бывает очень небольшим, например, вставка элемента в двусвязный список занимает не больше десятка инструкций. Каким же образом введение задержки может повысить производительность? Рассмотрим простой пример:
Допустим, этот код выполняется на двухпроцессорной машине и спин-блокировка не используется. Если два потока, выполняющиеся на разных процессорах, почти одновременно попытаются войти в критическую секцию, то события будут развиваться примерно следующим образом:
Как видно на схеме, из за того, что критическая секция была занята, второй поток был вынужден перейти в состояние ожидания, и, потенциально, CPU 2 перешел к выполнению другого потока. Только через некоторое время второй поток получит вновь управление и сможет войти в критическую секцию. При использовании спин-блокировки ситуация иная:
Cпин-блокировка заканчивается сразу же как только первый поток освободил критическую секцию. Как видно из рисунка, во втором случае второй поток получает доступ к критической секции гораздо быстрее, и, что самое важное, общее число производимых операций существенно меньше, так как не включает дорогую операцию переключения контекста. В случае с одним процессором применение спин-блокировки не имеет смысла. Если второй поток обнаруживает, что критическая секция занята, то единственный способ ее освободить — это дать выполняться первому потоку. Но у нас только один процессор, поэтому для того, чтобы первый поток смог возобновить выполнение, необходимо переключение контекста:
Если мы добавим спин-блокировку, то только отдалим тот момент, когда второй поток произведет неизбежное переключение контекста и первый поток освободит критическую секцию. |