K>"Для использования спин-блокировки в критической секции нужно инициализи ровать счетчик циклов, вызвав:

K>BOOL InitalizeCriticalSectionAndSpinCount( PCRITICAL_SECTION pcs, DWORD dwSpinCount);


K>Как и в InitializeCriticalSection, первый параметр этой функции — адрес структуры критической секции. Но во втором параметре, dwSpinCount, передается число циклов спин-блокировки при попытках получить доступ к ресурсу до перевода потока в состояние ожидания. Этот параметр может принимать значения от 0 до 0x00FFFFFF. Учтите, что на однопроцессорной машине значение параметра dwSpinCount игнорируется и считается равным 0. Дело в том, что применение спин-блокировки в такой системе бессмысленно: поток, владеющий ресурсом, не сможет освободить его, пока другой поток «крутится» в циклах спин-блокировки."


K> Не понятно почему на однопроцессорной машине, пока один поток крутиться в цикле, другой не сможет освободить ресурс. Если у нах одиноковый приоритет, то зацикленный поток по окончанию своего кванта прервется и другой поток сможет освободить ресурс(хотя смотря на чем прервался, наверное). При чем здесь кол-во процессоров?


Попробую я тоже объяснить своими словами. Цель введения спин-блокировки — увеличить производительность на многопроцессорных машинах. Дело в том, что переход потока в состояние ожидания и следующее за ним переключение контекста между потоками — это довольно длительная операция, сотни, если не тысячи инструкций процессора. В то же время фрагмент кода, защищаемый критической секцией, зачастую бывает очень небольшим, например, вставка элемента в двусвязный список занимает не больше десятка инструкций.

Каким же образом введение задержки может повысить производительность? Рассмотрим простой пример:

EnterCriticalSection(&g_crit);
InsertTailList(&g_ListHead, pEntry);
LeaveCriticalSection(&g_crit);


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

       -+------+------------------+-------+-------------------------------   -------------------------------------
        |      |                  |       |
CPU 1:  | Вход | Вставка элемента | Выход |                               ...
        |      |                  |       |
       -+--+---+------------------+-------+-----------------------------+-   -+------+------------------+-------+-
           | Неудачная попытка входа, которая заканчивается переходом в |     |      |                  |       |
CPU 2:     | состояние ожидания, и переключением процессора на другой   | ... | Вход | Вставка элемента | Выход |
           | поток                                                      |     |      |                  |       |
       ----+------------------------------------------------------------+-   -+------+------------------+-------+-


Как видно на схеме, из за того, что критическая секция была занята, второй поток был вынужден перейти в состояние ожидания, и, потенциально, CPU 2 перешел к выполнению другого потока. Только через некоторое время второй поток получит вновь управление и сможет войти в критическую секцию.

При использовании спин-блокировки ситуация иная:

       -+------+------------------+-------+------------------------------
        |      |                  |       |
CPU 1:  | Вход | Вставка элемента | Выход |
        |      |                  |       |
       -+--+---+------------------+-------+-+------------------+-------+-
           | Неудачная попытка входа, кото- |                  |       |
CPU 2:     | рая переходит в спин-блокиров- | Вставка элемента | Выход |
           | ку                             |                  |       |
       ----+--------------------------------+------------------+-------+-


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

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

       -+------+---------+------------------------------------------------+-
        |      |         | Первый поток исчерпал свой time slice, поэтому |
CPU 1:  | Вход | Вставка | происходит переключение контекста на второй    |   -->
        |      |         | поток                                          | 
       -+------+---------+------------------------------------------------+-
         \                          первый поток                         / \

       -+------------------------------------------------------------+----------+-------+-   -+-
        | Неудачная попытка входа, которая заканчивается переходом в |          |       |     |
 -->    | состояние ожидания, и переключением процессора на другой   | элемента | Выход | ... |   -->
        | поток                                                      |          |       |     |
       -+------------------------------------------------------------+----------+-------+-   -+-
       / \                        второй поток                      / \     первый поток

       -+------------------------------------------------+------+------------------+-------+-
        | Первый поток исчерпал свой time slice, поэтому |      |                  |       |
 -->    | происходит переключение контекста на второй    | Вход | Вставка элемента | Выход | ... 
        | поток                                          |      |                  |       |
       -+------------------------------------------------+------+------------------+-------+-
                   первый поток                         / \         второй поток


Если мы добавим спин-блокировку, то только отдалим тот момент, когда второй поток произведет неизбежное переключение контекста и первый поток освободит критическую секцию.
Автор: Alex Fedotov    Оценить