Критический раздел Windows - как полностью отключить вращение - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь установить счетчик вращений для CRITICAL_SECTION на ноль различными способами:

int main()
{
    CRITICAL_SECTION cs;

    ::InitializeCriticalSection(&cs);
    printf("Spin count by default %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);

    ::InitializeCriticalSectionAndSpinCount(&cs, 0);
    printf("Spin count with zero spin count init %08X\n", cs.SpinCount );
    ::DeleteCriticalSection(&cs);


    ::InitializeCriticalSectionEx(&cs, 0, 0);
    printf("Spin count with zero spin count and flags init %08X\n", cs.SpinCount );
    ::DeleteCriticalSection(&cs);

    ::InitializeCriticalSection(&cs);
    ::SetCriticalSectionSpinCount(&cs, 0);
    printf("Spin count after explicit reset to zero %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);
}

В Windows 7 все результаты равны 0, как и ожидалось.

В Windows 10 , кроме последней, все значения 0x020007D0.Последний результат дает 0x02000000.

По-видимому, 0x07D0 - это фактическое число оборотов (2000 в десятичном формате), а 0x02000000 - один из следующих флагов:

#define RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO         0x01000000
#define RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN          0x02000000
#define RTL_CRITICAL_SECTION_FLAG_STATIC_INIT           0x04000000
#define RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE         0x08000000
#define RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO      0x10000000

Боюсь, что RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN может вызвать вращение критической секции, даже если я попросил ее не вращаться с помощью SetCriticalSectionSpinCount.

Есть ли способ не определять RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN с помощью стандартных документированных API?

1 Ответ

0 голосов
/ 23 февраля 2019

После того, как заглянул в реализацию, сам разобрался с ответом.

Когда InitializeCriticalSectionEx используется с ненулевым счетчиком спинов, флаг RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN не устанавливается.Таким образом, этот код выводит 00000001:

::InitializeCriticalSectionEx(&cs, 1, 0);
printf("Spin count after explicit one %08X\n", cs.SpinCount);
::DeleteCriticalSection(&cs);

Один счетчик спинов почти равен нулю.И, кроме того, при вызове SetCriticalSectionSpinCount впоследствии его можно сбросить на ноль.Таким образом, этот код выводит 00000000:

::InitializeCriticalSectionEx(&cs, 1, 0);
::SetCriticalSectionSpinCount(&cs, 0);
printf("Spin count after explicit one and then reset to zero %08X\n", cs.SpinCount);
::DeleteCriticalSection(&cs);

Конечно, должна быть веская причина отключить вращение.По умолчанию, как указал @JonathanPotter, спиннинг хорош.В противном случае это не было бы установлено как поведение по умолчанию.Поэтому я даже не применил решение для отключения вращения к своей исходной задаче.

С другой стороны, сопровождающие критической секции не могут не уважать счетчик нулевого вращения, переданный в InitializeCriticalSectionEx, илиInitializeCriticalSectionAndSpinCount.Они просто убедились, что обычный InitializeCriticalSection получает автоматический счетчик спинов.

...