AutoResetEvent的这种用法会导致所描述的问题吗?

时间:2016-01-13 15:07:06

标签: c# .net-3.5 autoresetevent

我不习惯使用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 ...");
    }
}

单身人士使用AutoResetEvent ExecutionCompletedProgressCompleted,以及带有Completed旗帜同步锁的布尔

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(我的机器)上重现问题。 / p>

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

1 个答案:

答案 0 :(得分:2)

您可能需要考虑使用ManualResetEvent代替AutoResetEvent

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

ManualResetEvent会保持绿色,直到有人打电话给ResetAutoResetEvent会让一辆车进入并再次自动恢复到红灯状态。 您设置ProgressCompleted一次,但是等待两次,第一次在ShellApplication.Start,第二次在worker_DoWork。这意味着第二次等待将永远等待。

它永远不会失败的原因是因为if (!MySingleton.Instance.Completed)指示如果启动画面代码比后台工作者快,则不会等待第二次重置事件