gpt4 book ai didi

c# - WaitHandle.WaitAny 每次调用时都会分配 WaitHandle[] 的副本

转载 作者:行者123 更新时间:2023-11-30 15:35:06 29 4
gpt4 key购买 nike

我一直注意到对 WaitHandle.WaitAny 的调用会分配给它的 WaitHandle[] 的副本。从下面的链接或使用反射器可以看出:

http://reflector.webtropy.com/default.aspx/DotNET/DotNET/8@0/untmp/whidbey/REDBITS/ndp/clr/src/BCL/System/Threading/WaitHandle@cs/3/WaitHandle@cs

相关代码为:

    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
{
if (waitHandles==null)
{
throw new ArgumentNullException("waitHandles");
}
if (MAX_WAITHANDLES < waitHandles.Length)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_MaxWaitHandles"));
}
if (-1 > millisecondsTimeout)
{
throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
}
WaitHandle[] internalWaitHandles = new WaitHandle[waitHandles.Length];
for (int i = 0; i < waitHandles.Length; i ++)
{
WaitHandle waitHandle = waitHandles[i];

if (waitHandle == null)
throw new ArgumentNullException(Environment.GetResourceString("ArgumentNull_ArrayElement"));

if (RemotingServices.IsTransparentProxy(waitHandle))
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WaitOnTransparentProxy"));

internalWaitHandles[i] = waitHandle;
}
#if _DEBUG
// make sure we do not use waitHandles any more.
waitHandles = null;
#endif
int ret = WaitMultiple(internalWaitHandles, millisecondsTimeout, exitContext, false /* waitany*/ );
for (int i = 0; i < internalWaitHandles.Length; i ++)
{
GC.KeepAlive (internalWaitHandles[i]);
}
if ((WAIT_ABANDONED <= ret) && (WAIT_ABANDONED+internalWaitHandles.Length > ret))
{
int mutexIndex = ret -WAIT_ABANDONED;
if(0 <= mutexIndex && mutexIndex < internalWaitHandles.Length)
{
throw new AbandonedMutexException(mutexIndex,internalWaitHandles[mutexIndex]);
}
else
{
throw new AbandonedMutexException();
}
}
else
return ret;

}

现在我的问题是为什么?这是否可以规避(即编写自己的 WaitHandle.WaitAny 副本)?也许为什么不呢?

这意味着我的系统中有很多不必要的内存分配。由于低级别的方式,我们将其与多个 WaitHandles 一起使用。

请留在主题上,不要提及任务并行库或类似库;)我们在这里讨论的是 GC 压力很重要的高性能场景。

最佳答案

WaitMultiple 需要能够指望 WaitHandle 没有被垃圾回收。如果发生这种情况,可能会由于内存损坏或某些类似的问题而导致访问冲突。

我们的想法是,您应该能够调用 WaitMultiple 并销毁一个或多个 WaitHandle 对象,而 WaitAny 不会失败。如果它不创建一个副本,这将是不可能的,并且调试那个特定场景会花费你一整天的时间。所以最重要的是,它是为了线程安全而完成的。

如果您查看底层 native 函数的文档,WaitForMultipleObjects ,有证据表明:行为被描述为未定义:

If one of these handles is closed while the wait is still pending, the function's behavior is undefined.

如下文所建议的,如果充分利用它的所有性能很重要,您可以确保不释放 WaitHandles,并对 WaitForMultipleObjects 进行 p/invoke 调用。您可以提供 WaitHandle.SafeWaitHandle 作为相关同步对象的句柄。

编辑:上面给出的答案是错误的。我不时回到这个问题,因为它困扰着我;我现在相信我有一个正确的答案。

这种元素传输的目的是对各个 WaitHandle 进行线程安全验证。如果开发人员要使用原始数组,则其元素之一可能会被覆盖,例如 null 值,这将导致底层 native 函数出现未定义的行为。通过将元素复制到内部数组中,我们可以检查每个元素,如果它为 null 或无效则抛出异常,然后存储它。我们知道内部数组的元素不能被替换。因此,为了您很久以前的目的,如果您不做一些奇怪的事情,例如将 null 或跨 AppDomain 元素放入您的 WaitHandle 数组,您就可以了。

关于c# - WaitHandle.WaitAny 每次调用时都会分配 WaitHandle[] 的副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15367599/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com