首页 > 解决方案 > Windows 关键部分 - 如何完全禁用旋转

问题描述

我正在尝试通过不同的方法将 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 来定义?

标签: windowsmultithreadingwinapicritical-section

解决方案


在查看了实现之后,自己想出了答案。

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 指出的那样,旋转很好。否则它不会被设置为默认行为。所以我什至没有将禁用旋转的解决方案应用于我原来的问题。

另一方面,临界区的维护者可能无意不尊重传递给InitializeCriticalSectionExor的零自旋计数InitializeCriticalSectionAndSpinCount。他们只是确保平原InitializeCriticalSection获得自动旋转计数。


推荐阅读