C# 关闭多线程应用程序时已释放ObjectDisposed
可能重复:C# 关闭多线程应用程序时已释放ObjectDisposed,c#,multithreading,invoke,aforge,objectdisposedexception,C#,Multithreading,Invoke,Aforge,Objectdisposedexception,可能重复: **关于可能的重复-BackgroundWorker方法在此不适用 下面是我尝试使用一个RGE库来接收来自IP摄像机的视频 每个视频流都应该在单独的线程中运行,在新帧到达时通知UI线程。事件处理程序在引发它的同一线程中执行,因此我需要使用Invoke 在我希望停止应用程序之前,所有操作都会顺利运行。标有“>>>”的行引发ObjectDisposed异常,因此我的应用程序不会像运行时那样顺利结束 我知道问题在于理解多线程,只是因为它而看不到真正的问题。有人能解释一下这里发生了什么吗
**关于可能的重复-BackgroundWorker方法在此不适用 下面是我尝试使用一个RGE库来接收来自IP摄像机的视频 每个视频流都应该在单独的线程中运行,在新帧到达时通知UI线程。事件处理程序在引发它的同一线程中执行,因此我需要使用Invoke 在我希望停止应用程序之前,所有操作都会顺利运行。标有“>>>”的行引发ObjectDisposed异常,因此我的应用程序不会像运行时那样顺利结束 我知道问题在于理解多线程,只是因为它而看不到真正的问题。有人能解释一下这里发生了什么吗
Form1.cs
public void generic_NewFrame(object sender, NewFrameEventArgs e)
{
...
if (pictureBox1.InvokeRequired)
{
>>> pictureBox1.Invoke(new MethodInvoker(delegate()
{
pictureBox1.BackgroundImage = (Image)buf;
}));
}
else
{
pictureBox1.BackgroundImage = (Image)buf;
}
...
}
尽可能短,摄像机等级:
Camera.cs
//Camera thread loop
private void WorkerThread()
{
while (!stopEvent.WaitOne(0, false))
{
...
if (!stopEvent.WaitOne(0, false))
{
// notify UI thread
OnNewFrame(new NewFrameEventArgs(Last_frame));
...
}
}
override public void Play()
{
stopEvent = new ManualResetEvent(false);
thread = new Thread(new ThreadStart(WorkerThread));
thread.Start();
}
override public void Stop()
{
if (thread != null)
{
stopEvent.Set();
}
}
我认为问题在于:库在关闭表单后调用回调(
generic\u NewFrame
)。
你可以用几种不同的方法来修复它
首先,如果表单已被释放,则可以跳过回调方法:
public void generic_NewFrame(object sender, NewFrameEventArgs e)
{
// Lets skip this callback if our form already closed
**if (this.IsDisposed) return;**
...
if (pictureBox1.InvokeRequired)
{
>>> pictureBox1.Invoke(new MethodInvoker(delegate()
{
pictureBox1.BackgroundImage = (Image)buf;
}));
}
else
{
pictureBox1.BackgroundImage = (Image)buf;
}
...
}
另一种方法是等待而不是关闭表单,直到库仍在工作,然后在FormClosing
或FormClosing
事件处理程序中等待:
private void FormClosingEventHandler(object sender, CancelEventArgs e)
{
// Waiting till your worker thread finishes
_thread.Join();
}
或者,您可以使用停止方法等待:
override public void Stop()
{
if (thread != null)
{
stopEvent.Set();
thread.Join();
}
}
我认为问题在于:库在关闭表单后调用回调(
generic\u NewFrame
)。
你可以用几种不同的方法来修复它
首先,如果表单已被释放,则可以跳过回调方法:
public void generic_NewFrame(object sender, NewFrameEventArgs e)
{
// Lets skip this callback if our form already closed
**if (this.IsDisposed) return;**
...
if (pictureBox1.InvokeRequired)
{
>>> pictureBox1.Invoke(new MethodInvoker(delegate()
{
pictureBox1.BackgroundImage = (Image)buf;
}));
}
else
{
pictureBox1.BackgroundImage = (Image)buf;
}
...
}
另一种方法是等待而不是关闭表单,直到库仍在工作,然后在FormClosing
或FormClosing
事件处理程序中等待:
private void FormClosingEventHandler(object sender, CancelEventArgs e)
{
// Waiting till your worker thread finishes
_thread.Join();
}
或者,您可以使用停止方法等待:
override public void Stop()
{
if (thread != null)
{
stopEvent.Set();
thread.Join();
}
}
要避免导致这种情况的竞争条件,可以执行以下操作:
pictureBox1.Invoke(new MethodInvoker(delegate()
{
if (!pictureBox1.IsDisposed)
{
pictureBox1.BackgroundImage = (Image)buf;
}
}));
重要的是在UI线程上检查
IsDisposed
,即在被调用的委托内部。要避免导致这种情况的争用条件,可以执行以下操作:
pictureBox1.Invoke(new MethodInvoker(delegate()
{
if (!pictureBox1.IsDisposed)
{
pictureBox1.BackgroundImage = (Image)buf;
}
}));
重要的是在UI线程上检查
IsDisposed
,即在被调用的委托内部。使用thread.Join()可防止表单关闭完成。不知何故,工作线程上的NewFrame永远不会结束,不管我是否检查pictureBox1.IsDisposed。好的,似乎用BeginInvoke替换Invoke解决了这个问题。老实说,我想了解为什么~~调用是一个同步调用。这意味着您将等待底层主体执行。我强烈建议找出问题的根源,而不是使用BeginInvoke。我假设对thread.Join()的调用会导致死锁,这就是表单不关闭的原因。如果(this.IsDisposed)返回;-值得怀疑,因为泛型_NewFrame没有在UI线程中执行。也许,如果我在UI线程上调用整个泛型_NewFrame,它会起作用。这似乎很合理,因为工作线程不应该过载,除了它们的直接用途之外。我试试看,谢谢。但是,如果在同一个线程上执行NewFrame和FormClosing,则无法确定竞态条件将如何改变。使用thread.Join()可防止FormClosing完成。不知何故,工作线程上的NewFrame永远不会结束,不管我是否检查pictureBox1.IsDisposed。好的,似乎用BeginInvoke替换Invoke解决了这个问题。老实说,我想了解为什么~~调用是一个同步调用。这意味着您将等待底层主体执行。我强烈建议找出问题的根源,而不是使用BeginInvoke。我假设对thread.Join()的调用会导致死锁,这就是表单不关闭的原因。如果(this.IsDisposed)返回;-值得怀疑,因为泛型_NewFrame没有在UI线程中执行。也许,如果我在UI线程上调用整个泛型_NewFrame,它会起作用。这似乎很合理,因为工作线程不应该过载,除了它们的直接用途之外。我试试看,谢谢。但是,如果在同一线程上执行NewFrame和FormClosing,则不确定竞争条件将如何改变。