AutoResetEvent 的这种使用是否会导致所描述的问题?

Could this usage of AutoResetEvent be causing the issue described?

我不习惯使用 AutoResetEvent,我想知道以下情况是如何发生的。

我们有一个日志文件,它始终记录在两台不同机器上的不同加载操作顺序:

机器A(出现问题)

Loading Module A
Loading Module B
Loading Shell.
Show Window.
Waiting Until Services are Loaded & Initialized.
Loading Module C
Starting Application ..

机器B(普通日志文件)

Loading Module A
Loading Module B
Loading Module C
Starting Application ..
Loading Shell.
Show Window.
Initializing Menu Elements ...

第一台机器从不加载菜单元素。

代码是这样的:

public class SplashScreen : Form
{
    // SplashScreen.Run method which signals the ProgressCompleted event
    private void Run()
    {
        // some code

        MySingleton.Instance.ExecutionCompleted.WaitOne();
        MySingleton.Instance.Completed = true;
        MySingleton.Instance.ProgressCompleted.Set();

        // more code
    }
}

public class ShellApplication : FormShellApplication<WorkItem, ShellForm>
{    
    // ShellApplication.Start override
    protected override void Start()
    {
        MySingleton.Instance.ProgressCompleted.WaitOne();
        WriteToLog("Starting Application ..");
        base.Start();
    }
}

public class ShellForm : Form
{    
    // Background worker that runs from ShellForm.Load
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        // check to ensure services & ui components are loaded & initialized 
        if (!MySingleton.Instance.Completed)
        {
            WriteToLog("Waiting Until Services are Loaded & Initialized.");
            MySingleton.Instance.ProgressCompleted.WaitOne();
        }
    }

    // Background worker’s RunWorkerCompleted that runs from ShellForm.Load
    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // Some Code
        WriteToLog("Initializing Menu Elements ...");
    }
}

单例对ExecutionCompletedProgressCompleted使用AutoResetEvent,对Completed标志

使用带同步锁的bool
public class MySingleton
{
    private object _sync = new object();

    private static AutoResetEvent _executionCompleted = new AutoResetEvent(false);
    private static AutoResetEvent _progressCompleted = new AutoResetEvent(false);
    private static bool _completed = false;

    public AutoResetEvent ProgressCompleted
    {
        get
        {
            lock (_sync)
            {
                return _progressCompleted;
            }
        }
    }

    public AutoResetEvent ExecutionCompleted
    {
        get 
        {
            lock (_sync)
            {
                return _executionCompleted;
            }
        }
    }

    public bool Completed
    {
        get
        {
            lock (_sync)
            {
                return _completed;
            }
        }
        set
        {
            lock (_sync)
            {
                _completed = value;
            }
        }
    }
}

据我所知,在机器 A 上,后台工作程序似乎在所有模块加载之前启动,并且 ProgressCompleted.WaitOne() 要么从未命中,要么在 .Completed 标志为 false 时被命中.我对 AutoResetEvent 没有足够的经验,无法知道代码中是否有任何内容会导致此问题,例如第二次 .WaitOne 调用它。

我不认为这是与同步锁定相关的时间问题,因为它在机器 A 上每次都会发生,而我无法在机器 B(我的机器)上重现该问题。

上面的代码中是否有任何与 AutoResetEvent 用法相关的内容可能会导致此异常行为?我正在使用 .Net 3.5。

您可能要考虑使用 ManualResetEvent 而不是 AutoResetEvent

重置事件就像红绿灯。由于您使用 false 初始化它,因此它以红灯开始。 当你 set 它时,它会变成绿色。 ManualResetEventAutoResetEvent 之间的区别在于它保持绿色的时间...

ManualResetEvent 将保持绿色,直到有人在其上调用 ResetAutoResetEvent 将让一辆车进入并自动恢复为红灯。 您设置了一次 ProgressCompleted,但等待了两次,第一次是在 ShellApplication.Start,第二次是在 worker_DoWork。意味着第二次等待将永远等待。

它不会总是失败的原因是 if (!MySingleton.Instance.Completed) 如果初始屏幕代码比后台工作程序快,它规定您不会第二次等待重置事件。