疑为多线程UI引发的的异常

truexxg 2009-05-11 11:03:31
程序是这样的:

窗体调用了一个dll模块(若干类),这个模块进行异步通讯,快速的收到很多数据,并根据数据生成了一个bitmap的一行,触发事件linefinished。主窗体中订阅这个事件,并需要飞快的更新Picturebox 显示生成的bitmap。

现在的问题是,会出现两种异常。
第一种是,刷新picture时bitmap对象正在使用中。
我尝试用synclock在生成bitmap和现实bitmap的地方进行互斥锁,但是还是偶尔出现对象正在使用的异常。

第二种很致命,在刷新picture时,对窗体进行可能会引发重绘的操作(窗体mousedown、窗体拖动、最大化等)导致对象正在使用中的异常,但不知道是哪个异常。据我怀疑是有2个线程(窗体操作线程和订阅的linefinished事件)同时重绘导致的。

错误信息如下:
未处理 System.InvalidOperationException
Message="对象当前正在其他地方使用。"
Source="System.Drawing"
StackTrace:
在 System.Drawing.Image.get_RawFormat()
在 System.Drawing.Graphics.IgnoreMetafileErrors(Image image, Int32& errorStatus)
在 System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y, Int32 width, Int32 height)
在 System.Drawing.Graphics.DrawImage(Image image, Rectangle rect)
在 System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
在 System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
在 System.Windows.Forms.Control.WmPaint(Message& m)
在 System.Windows.Forms.Control.WndProc(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.Run(ApplicationContext context)
在 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
在 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
在 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
在 STM_Controller.My.MyApplication.Main(String[] Args) 位置 17d14f5c-a337-4978-8281-53493378c1071.vb:行号 81
在 System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
在 System.Threading.ThreadHelper.ThreadStart()

我不知道VB的main函数在哪里,也不知道这个问题如何解决。请教各位大大,这个问题该怎么办?
若不能在子线程所在的dll模块中,调用外部窗体invoke方法的话,这个程序又该如何设计?


我尝试过的方法:
bitmap.clone不能解决异常二;
刷新由linefinished触发,改为窗体Timer_tick事件触发,不能解决异常二;
刷新语句用try Catch包住,依然不能解决异常二。
……

怎么办怎么办????
...全文
239 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
truexxg 2009-05-15
  • 打赏
  • 举报
回复
非常感谢大家的帮助。
gxj760998 2009-05-12
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 snakegod 的回复:]
有个建议 刷新页面主窗体自己开线程来做,一秒掉一次。别用子线程来掉,如果数据多 每秒掉几十次你不晕死。即使用invoke也不行。再说你又不是放电影,用不着每秒那么多帧。其实2到3秒一帧都可以了。人眼睛又不是高速摄影机。
[/Quote]
的确,应该考虑实际应用水准和要求。
李世垚 2009-05-12
  • 打赏
  • 举报
回复
有个建议 刷新页面主窗体自己开线程来做,一秒掉一次。别用子线程来掉,如果数据多 每秒掉几十次你不晕死。即使用invoke也不行。再说你又不是放电影,用不着每秒那么多帧。其实2到3秒一帧都可以了。人眼睛又不是高速摄影机。
wangan2008 2009-05-12
  • 打赏
  • 举报
回复
学习~
yanlongwuhui 2009-05-12
  • 打赏
  • 举报
回复
在循环体内声明bitmap对象变量(例如ctlObject),使用后及时释放(ctlObject=nothing)
yanlongwuhui 2009-05-12
  • 打赏
  • 举报
回复
建议附上代码
Fibona 2009-05-11
  • 打赏
  • 举报
回复
当你用线程或者其它来操作窗体的控件时,因为你已经离开了主窗体(主线程),除了考虑线程同步外,本身应该是通过一个委托单独来处理
比如说你的线程类触发一个事件,需要回调主窗体
然后你要处理多线程或者其它的你只要在回调处理函数里面处理就行了
下面给一个demo

Server server=new 你的socketServer();
server.onMessage+= new 你的socketServer.EventHandler(server_Message);

private void server_Message(object sender, Exception e)
{
ListBoxAdd(System.DateTime.Now.ToString() + " " + e.Message);
}

delegate void ListBoxAddCallback(string item);

private void ListBoxAdd(string s)
{
if (this.lsResult.InvokeRequired)
{
ListBoxAddCallback d = new ListBoxAddCallback(ListBoxAdd);
this.Invoke(d, new object[] { s });
}
else
{
this.lsResult.Items.Add(s);
if (lsResult.Items.Count > 100)
{
lsResult.Items.Clear();
}
}
}
周公 2009-05-11
  • 打赏
  • 举报
回复
当你用线程或者其它来操作窗体的控件时,因为你已经离开了主窗体(主线程),除了考虑线程同步外,本身应该是通过一个委托单独来处理.
对于控件都提供Invoke方法,改方法需要一个delegate作为参数,通过Invoke来操作控件就不会出现你说的问题了。
cnzdgs 2009-05-11
  • 打赏
  • 举报
回复
刷新操作应该在窗体所属线程中进行,在窗体中定义方法,线程中通过Invoke调用。

16,554

社区成员

发帖
与我相关
我的任务
社区描述
VB技术相关讨论,主要为经典vb,即VB6.0
社区管理员
  • VB.NET
  • 水哥阿乐
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧