在多线程同时绘图时,绘制内容稍多时,极易发生撞车,报 Object is in use 错误。
多线程绘图有两种:一为新线程会覆盖老线程。也就是说,新线程创建后,老线程应该作废。
二为新线程和老线程分工独立,两个都要绘制。前一种情形下的处理本应调用 aThread.Abort() 后执行 bThread,然而,Abort 消耗时间很长,画面将不流畅。我目前借助一个全局流水 id, 启动 bThread 时,给线程分配一个新 id, 线程内每步都检查它拿到的 id 是否已经小于当前全局 id, 不检查便退出。
这个方法可以达到目的,但很麻烦,每绘制一步需要检查一次。当需要进一步封装时,由于可能已超出 id 所在的可见域,该方法会失效。后一种情形,似可借助线程队列来做,情况更显复杂。在动手写代码前咨询一下大侠,有没有更好的办法处理多线程抢 Graphics 的问题。谢谢。
多线程绘图有两种:一为新线程会覆盖老线程。也就是说,新线程创建后,老线程应该作废。
二为新线程和老线程分工独立,两个都要绘制。前一种情形下的处理本应调用 aThread.Abort() 后执行 bThread,然而,Abort 消耗时间很长,画面将不流畅。我目前借助一个全局流水 id, 启动 bThread 时,给线程分配一个新 id, 线程内每步都检查它拿到的 id 是否已经小于当前全局 id, 不检查便退出。
这个方法可以达到目的,但很麻烦,每绘制一步需要检查一次。当需要进一步封装时,由于可能已超出 id 所在的可见域,该方法会失效。后一种情形,似可借助线程队列来做,情况更显复杂。在动手写代码前咨询一下大侠,有没有更好的办法处理多线程抢 Graphics 的问题。谢谢。
你的graphic对象那么在多线程的时候肯定回发生句柄错误“used in ortherwise...等等错误”
建议把你的画图方法写在Paint函数下。在外部调用的时候时候使用Invalidata()方法。这用就不会出现你所担心的问题了
http://blog.csdn.net/knight94/archive/2006/03/22/632512.aspx方法是一样的,不过转换成画图而已
用lock锁定你要绘制的对象,这样就能实现线程间互斥了
lock 之后的确会形成一个等待,适合第一种情形的处理。
互斥体有单件的效果,可以应付第二种情形。因为没想到 lock (VB.net 叫 SyncLock,汗)我自己做了一个类,亦实现了相似功能,一个类属 bool 变量 + sleep 实现 lock 的效果,当然,比起语言级别的实现来说显得笨拙很多;一个静态成员实现互斥体的效果,比互斥体效果好,具体细节不再赘述。但在实际运用时,发现依然有问题。
比方我地图上有精灵,现在地图和精灵两个离屏都可以如愿以偿的绘制,不再出抢 Graphics 用的错误。但如果地图控件本身有一些控件显示隐藏的操作,会导致地图重绘,此时依然会引发 object in use 错误。关于这个问题,我想需要探知 graphics 可否使用(可否 getHdc)才是最终办法。
你可以用Graphics.GetHDC获得hdc,但是还是会出现上面的现象
不过也好,这样不用去找检验 dc 能用的函数了。
这个是标准的windows体系的消息处理方式,其实就是只有一个线程来处理画图
如果要多个线程都来画图,这个只能发生冲突
要么就是创建互斥量,你自己写的类基本上肯定不行的,本身就会发生不能互斥的情况,因为在多个线程当中进行
个人认为这个跟多线程没有关系,这个和Graphic有关。如果你用的this.CreateGraphic()去生成
你的graphic对象那么在多线程的时候肯定回发生句柄错误“used in ortherwise...等等错误”
建议把你的画图方法写在Paint函数下。在外部调用的时候时候使用Invalidata()方法。这用就不会出现你所担心的问题了
================================================================
我喜欢用这种方法,至于双缓冲,我会用窗体Form类的SetStyle()来让它自动实现双缓冲
public void EnableDoubleBuffering()
{
// Set the value of the double-buffering style bits to true.
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}
现在记起为什么以前用流水号,以前那个用流水号的办法可以解决这个问题,因为新的线程需要立刻取代老的线程。
noky(孤狼傲血) 的方法是对的
这个是标准的windows体系的消息处理方式,其实就是只有一个线程来处理画图
如果要多个线程都来画图,这个只能发生冲突
要么就是创建互斥量,你自己写的类基本上肯定不行的,本身就会发生不能互斥的情况,因为在多个线程当中进行不能用互斥体,假如我窗口上要放两个地图控件,我这两个控件都在渲染,用互斥体会发生甲控件锁乙控件的情况。我用了一个 static Dictionary<control,bool>。
public void EnableDoubleBuffering()
{
// Set the value of the double-buffering style bits to true.
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}恩,.net 2.0 包含了 BufferGraphics 的处理。通过代码,可以申请更多数目的离屏。通过什么方式实现双缓冲,并不是问题的关键。