C#报”WaitHandleCannotBeOpenedException”的原因以及解决办法

  • Post category:C#

“WaitHandleCannotBeOpenedException”是一个.NET平台的异常,表示尝试打开操作系统中不存在或无法打开的等待处理句柄(Wait Handle Handle)。

造成该异常的原因可能包括但不限于以下情况:
1. 指定的句柄不存在或已被关闭。
2. 使用了错误的访问权限或访问模式。
3. 等待句柄的进程已经终止。
4. 并发访问产生了冲突。

针对以上情况,下面提供两种可能的解决方法:

方法一:排查句柄是否存在并确保访问正确
当出现该异常时,首先需要排查对应的等待处理句柄是否存在,以及对该句柄的访问权限是否被授予。同时,我们也需要检查当前线程可能的并发冲突,例如多线程访问同样的句柄等情况。

示例:

using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // 创建一个 ManualResetEvent
        ManualResetEvent mre1 = new ManualResetEvent(false);
        ManualResetEvent mre2 = new ManualResetEvent(false);

        // 打开一个不存在的WaitHandle
        ThreadPool.QueueUserWorkItem(state => {
            try {
                WaitHandle.WaitAny(new WaitHandle[] { mre1, mre2, new ManualResetEvent(false) });
            } catch (WaitHandleCannotBeOpenedException e) {
                Console.WriteLine(e.Message);  // 输出 WaitHandle cannot be opened because it has been closed or no longer exists.
            }
        });

        // 释放所有句柄,模拟WaitAny已经结束了
        mre1.Set();
        mre1.Dispose();
        mre2.Set();
        mre2.Dispose();

        Console.ReadLine();
    }
}

在上面的示例中,我们模拟了一个WaitHandle不存在或已关闭的情况,通过释放所有相关句柄来结束WaitAny的等待,同时在异常处理中输出了详细的异常信息。

方法二:考虑其他合适的等待处理方式
除了WaitHandle,.NET平台提供了其他多种等待处理方式,可以根据具体的需求来选择合适的方式,以避免WaitHandleCannotBeOpenedException的出现。

示例:

using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Task<int> t1 = Task.Run(() => {
            // 模拟长时间执行的任务
            return Task.Delay(2000).ContinueWith<int>(t => 1);
        });

        // 如果t1在1s内还没有完成,则返回-1
        int result = Task.WaitAny(new Task[] { t1 }, 1000);
        Console.WriteLine(result == 0 ? t1.Result.ToString() : "-1");

        Console.ReadLine();
    }
}

在上面的示例中,我们使用了Task.Delay模拟了一个长时间执行的任务,同时使用Task.WaitAny代替等待处理句柄的方式等待t1的完成,其中,如果t1在1s内还没有返回结果,则直接返回-1,不会抛出WaitHandleCannotBeOpenedException的异常。

以上示例仅供参考,具体的解决方法需要根据实际情况进行选择,在保证性能和减少异常出现的同时,尽可能遵守.NET平台的规范和最佳实践。