最近在工作中遇到一個問題,就是我有多個線程會調用bitmap對象,運行的時候報錯,對象當前正在其他地方使用。第一反應肯定是加鎖啊,於是我就在每個用到bitmap的地方都加了鎖,但是運行之後依然報這個錯 測試代碼如下 using System; using System.Drawing; using ...
最近在工作中遇到一個問題,就是我有多個線程會調用bitmap對象,運行的時候報錯,對象當前正在其他地方使用。第一反應肯定是加鎖啊,於是我就在每個用到bitmap的地方都加了鎖,但是運行之後依然報這個錯
測試代碼如下
using System; using System.Drawing; using System.Threading; using System.Windows.Forms; namespace BitMapLockTest { public partial class Form1 : Form { private Bitmap testBitmap; private static readonly object obj = new object(); public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { testBitmap = new Bitmap(100, 100); Thread th = new Thread(DrawBackGround); th.IsBackground = true; th.Start(); } private void DrawBackGround() { while (true) { lock (obj) { Graphics g = Graphics.FromImage(testBitmap); g.Clear(Color.White); g.Dispose(); } } } private void button1_Click(object sender, EventArgs e) { lock (obj) { Graphics g = Graphics.FromImage(testBitmap); g.FillRectangle(new SolidBrush(Color.FromArgb(100, 200, 2)), new Rectangle(new Point(0, 0), new Size(20, 20))); g.Dispose(); Updatepic(testBitmap); } } private void Updatepic(Bitmap bitmap) { if (pictureBox1.InvokeRequired) { Invoke(new Action<Bitmap>(Updatepic), bitmap); } else { lock (obj) { pictureBox1.Image = bitmap; } } } } }
網上也有之類的問題,都是告訴我,不應該多線程使用bitmap對象,如果有需求,可以用bitmap.clone().
改了下
private void button1_Click(object sender, EventArgs e) { lock (obj) { Graphics g = Graphics.FromImage(testBitmap); g.FillRectangle(new SolidBrush(Color.FromArgb(100, 200, 2)), new Rectangle(new Point(0, 0), new Size(20, 20))); g.Dispose(); Updatepic((Bitmap)testBitmap.Clone()); } }
OK,不報錯了。但我的疑問沒解除啊
你得告訴我為啥鎖不住啊?難道是lock(obj)寫的不對?那我換成 lock (testBitmap)總行了吧,依然報錯。。。
後來我想了下。終於想明白了
問題出來這裡
pictureBox1.Image = bitmap;
bitmap是個引用對象,把他賦值給pictureBox1的Image屬性之後。pictureBox1所在的UI線程就一直保持了對bitmap對象的引用。所以別的線程加了鎖也沒用,依然會報錯。
用clone方法複製對象的根本原因,就是避免了UI對原對象的引用。
我以為在所有引用bitmap的地方都加了鎖不應該有問題了,卻忘了。UI線程對其的引用。
低級錯誤。。。