自动重置事件的这种用法是否会导致所描述的问题
本文关键字:问题 描述 是否 事件 用法 | 更新日期: 2023-09-27 18:30:04
我不习惯使用AutoResetEvent
,并且想知道以下情况是如何发生的。
我们有一个日志文件,它始终在两台不同的机器上记录不同的加载操作顺序:
机器 A(出现问题(
加载模块 A加载模块 B加载外壳。显示窗口。等到服务加载和初始化。装载模块 C正在启动应用程序..
机器 B(普通日志文件(
加载模块 A加载模块 B装载模块 C正在启动应用程序..加载外壳。显示窗口。正在初始化菜单元素...
第一台计算机从不加载菜单元素。
代码是这样的:
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
表示ExecutionCompleted
和ProgressCompleted
,并使用带有同步锁的布尔值表示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
标志为假时被击中。我没有足够的AutoResetEvent
经验来知道代码中是否有任何内容会导致这种情况,例如对它的第二次.WaitOne
调用。
我不认为这是与同步锁相关的计时问题,因为它每次都在机器 A 上发生,而我无法在机器 B(我的机器(上重现问题。
上面的代码中是否有任何与AutoResetEvent
用法相关的内容可能导致此异常行为?我正在使用.Net 3.5。
考虑使用 ManualResetEvent
而不是 AutoResetEvent
。
重置事件就像一个红绿灯。由于您用false
初始化它,因此它以红灯开始。当您set
它时,它会变成绿色。ManualResetEvent
和AutoResetEvent
之间的区别在于它在绿色上停留了多长时间......
ManualResetEvent
将保持绿色,直到有人打电话给Reset
。 AutoResetEvent
会让一辆车进入并再次自动恢复到红灯。您设置了一次ProgressCompleted
,但您等待了两次,第一次是在ShellApplication.Start
,第二次是在worker_DoWork
。这意味着第二次等待将永远等待。
它不会总是失败的原因是if (!MySingleton.Instance.Completed)
,如果初始屏幕代码比后台辅助角色快,则不要第二次等待重置事件。