首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WaitHandle.WaitAny在每次调用时都会分配WaitHandle[]的副本

WaitHandle.WaitAny在每次调用时都会分配WaitHandle[]的副本
EN

Stack Overflow用户
提问于 2013-03-13 01:06:51
回答 1查看 962关注 0票数 3

我已经注意到,对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

相关代码为:

代码语言:javascript
复制
    [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压力很重要的高性能场景。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-13 01:18:17

WaitMultiple需要能够指望WaitHandle不会被垃圾回收。如果发生这种情况,可能会因为内存损坏或某种类似的肮脏情况而导致访问冲突。

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

如果您查看一下底层本机函数WaitForMultipleObjects的文档,就会发现有证据表明:行为被描述为未定义的:

如果在等待仍处于挂起状态时关闭其中一个句柄,则函数的行为未定义。

如下所示,如果需要尽可能提高性能,那么可以确保调用不会被释放,并对WaitForMultipleObjects进行p/ WaitHandles调用。您可以提供WaitHandle.SafeWaitHandle作为有问题的同步对象的句柄。

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

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

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15367599

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档