【问题标题】:Slow communication using shared memory between user mode and kernel在用户模式和内核之间使用共享内存进行慢速通信
【发布时间】:2019-07-27 17:08:08
【问题描述】:

我正在 Windows 内核中运行一个线程,该线程通过共享内存与应用程序通信。一切正常,除了由于睡眠循环而导致通信缓慢。我一直在研究自旋锁、互斥锁和互锁,但无法真正弄清楚这一点。我也考虑过 Windows 事件,但不知道那个事件的性能。请建议什么是更快的解决方案,通过共享内存保持通信可能暗示 Windows 事件。

内核代码

typedef struct _SHARED_MEMORY
{
    BOOLEAN mutex;
    CHAR data[BUFFER_SIZE];
} SHARED_MEMORY, *PSHARED_MEMORY;

ZwCreateSection(...)
ZwMapViewOfSection(...)

while (TRUE) {
    if (((PSHARED_MEMORY)SharedSection)->mutex == TRUE) {
      //... do work...
      ((PSHARED_MEMORY)SharedSection)->mutex = FALSE;
    }
    KeDelayExecutionThread(KernelMode, FALSE, &PollingInterval);
}

申请代码

OpenFileMapping(...)
MapViewOfFile(...)

...

RtlCopyMemory(&SM->data, WriteData, Size);
SM->mutex = TRUE;

while (SM->mutex != FALSE) {
    Sleep(1); // Slow and removing it will cause an infinite loop
}

RtlCopyMemory(ReadData, &SM->data, Size);

更新 1 目前这是我想出的最快的解决方案:

while(InterlockedCompareExchange(&SM->mutex, FALSE, FALSE));

但是我觉得很有趣的是你需要做一个交换并且没有只比较的功能。

【问题讨论】:

    标签: c++ windows kernel mutex spinlock


    【解决方案1】:

    您不想使用 InterlockedCompareExchange。它会消耗 CPU,使共享该物理内核的另一个线程可能需要的内核资源饱和,并且会使内核间总线饱和。

    你确实需要做两件事:

    1) 编写一个InterlockedGet 函数并使用它。

    2) 防止循环消耗 CPU 资源并在最终解除阻塞时占用所有错误预测分支的母亲。

    对于 1,众所周知,这适用于所有支持 InterlockedCompareExchange 的编译器,至少在我上次检查时:

    __inline static int InterlockedGet(int *val)
    {
        return *((volatile int *)val);
    }
    

    对于 2,将其作为等待循环的主体:

    __asm
    {
        rep nop
    }
    

    对于 x86 CPU,这是为了解决资源饱和和分支预测问题而指定的。

    把它放在一起:

    while ((*(volatile int *) &SM->mutex) != FALSE) {
        __asm
        {
            rep nop
        }
    }
    

    如果不合适,请根据需要更改int

    【讨论】:

    • 很好的答案,谢谢!只是一个问题,我注意到您没有调用内联函数,而是添加了 volatile 指针,我理解它是同一件事,但只是想确定一下。该架构也是 64 位的,因此 __asm 无法工作。 64位的等价物是什么?也许是 YieldProcessor()?
    • 是的,你可以使用内联函数或者直接拼接进去,哪个更方便。有关YieldProcessor 及其各种实现的信息,请参阅here。其中之一应该适合你。 (该评论具有误导性。无论是否使用超线程,它还将解决功耗和分支预测问题。该评论告诉您 MS 保证它会做什么。英特尔和 AMD 指定它会做更多。 )
    • 非常感谢,我现在会接受这个,因为你已经给出了一个完美的答案。我还有一个关于内核代码的问题,我想知道您是否在等待过程 KeDelayExecutionThread 上有任何 cmets,或者我是否应该使用 KeStallExecutionProcessor 来获得大约 50-100 微秒的暂停。我应该提出一个新问题吗?
    • @illion 可能,因为我对 Windows 内核节点了解不多。
    猜你喜欢
    • 2015-12-12
    • 2021-11-04
    • 2015-06-04
    • 1970-01-01
    • 2012-03-02
    • 2023-03-15
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多