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 ...");
}
}
单例对ExecutionCompleted
和ProgressCompleted
使用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
它时,它会变成绿色。
ManualResetEvent
和 AutoResetEvent
之间的区别在于它保持绿色的时间...
ManualResetEvent
将保持绿色,直到有人在其上调用 Reset
。
AutoResetEvent
将让一辆车进入并自动恢复为红灯。
您设置了一次 ProgressCompleted
,但等待了两次,第一次是在 ShellApplication.Start
,第二次是在 worker_DoWork
。意味着第二次等待将永远等待。
它不会总是失败的原因是 if (!MySingleton.Instance.Completed)
如果初始屏幕代码比后台工作程序快,它规定您不会第二次等待重置事件。
我不习惯使用 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 ...");
}
}
单例对ExecutionCompleted
和ProgressCompleted
使用AutoResetEvent
,对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(我的机器)上重现该问题。
上面的代码中是否有任何与 AutoResetEvent
用法相关的内容可能会导致此异常行为?我正在使用 .Net 3.5。
您可能要考虑使用 ManualResetEvent
而不是 AutoResetEvent
。
重置事件就像红绿灯。由于您使用 false
初始化它,因此它以红灯开始。
当你 set
它时,它会变成绿色。
ManualResetEvent
和 AutoResetEvent
之间的区别在于它保持绿色的时间...
ManualResetEvent
将保持绿色,直到有人在其上调用 Reset
。
AutoResetEvent
将让一辆车进入并自动恢复为红灯。
您设置了一次 ProgressCompleted
,但等待了两次,第一次是在 ShellApplication.Start
,第二次是在 worker_DoWork
。意味着第二次等待将永远等待。
它不会总是失败的原因是 if (!MySingleton.Instance.Completed)
如果初始屏幕代码比后台工作程序快,它规定您不会第二次等待重置事件。