【问题标题】:Thread conflict in c#c#中的线程冲突
【发布时间】:2013-06-13 12:30:03
【问题描述】:

我用 C# 编写了以下代码:

private void myEnqThread()
        {
            Bitmap temp = null;
            temp = getScreen();
            if(temp!=null)
                queueScreen.Enqueue(temp);
        }

        private Bitmap getScreen(){
            System.Drawing.Bitmap bitmapDesktop;
            System.Drawing.Graphics graphics;
            System.IntPtr hWndForeground;// = System.IntPtr.Zero;

            RECT rect = new RECT();
            bitmapDesktop = null;
            graphics = null;
            hWndForeground = System.IntPtr.Zero;

            bitmapDesktop = new Bitmap
            (
                System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width,
                System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height,
                System.Drawing.Imaging.PixelFormat.Format24bppRgb
            );

            graphics = System.Drawing.Graphics.FromImage(bitmapDesktop);
            graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);
            hWndForeground = GetForegroundWindow();
            GetWindowRect(hWndForeground, out rect);
            graphics.DrawRectangle(Pens.Red, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
            return bitmapDesktop;
        }

可以存在多个执行 myEnqThread() 方法的线程 例如:

Thread oThreadEnqueue = new Thread(new ThreadStart(myEnqThread));
oThreadEnqueue.Start();
Thread oThreadEnqueue2 = new Thread(new ThreadStart(myEnqThread));
oThreadEnqueue2.Start();

我得到错误:

ArgumentException not managed. 

错误如下图所示:

我想这种情况只有在多个线程尝试访问该操作时才会发生,因为当我只使用一个线程尝试相同的代码时,没有问题。

我可以做些什么来解决这个问题?我可以锁定资源吗?

编辑:

在@Oscar 建议的更改后,我得到了 错误

【问题讨论】:

  • 您不应该从 UI 线程以外的任何线程处理 UI 元素。
  • ArgumentException 表示参数无效。当未绘制屏幕且未定义边界值时,是否可以调用此方法?抛出异常时,查看调试器中的宽度和高度值,看看它们是否已定义。

标签: c# .net multithreading thread-safety threadpool


【解决方案1】:

看来你需要在调用之前创建一个锁

graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size);

我也建议在 finally 块中的代码中对所有 IDisposbale 实例(如 Graphics 和 Bitmap)调用 Dispose()。

编辑:刚刚修改了您的代码。它没有经过测试,所以要小心。

public class MyClass{

private static readonly Object objLock = new Object();
private void myEnqThread()
        {
            Bitmap temp = null;
            temp = getScreen();
            if(temp!=null)
                queueScreen.Enqueue(temp);
        }

        private Bitmap getScreen(){
            System.Drawing.Bitmap bitmapDesktop;
            System.Drawing.Graphics graphics;
            System.IntPtr hWndForeground;// = System.IntPtr.Zero;

            RECT rect = new RECT();
            bitmapDesktop = null;
            graphics = null;
            hWndForeground = System.IntPtr.Zero;
            lock(objLock){
                bitmapDesktop = new Bitmap
                (
                        System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width,
                    System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height,
                    System.Drawing.Imaging.PixelFormat.Format24bppRgb
                );

                graphics = System.Drawing.Graphics.FromImage(bitmapDesktop);
                hWndForeground = GetForegroundWindow();
                GetWindowRect(hWndForeground, out rect);
                graphics.DrawRectangle(Pens.Red, rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
                return bitmapDesktop;
            }
        }   

}

随意移动锁,如有必要,可以移动到方法的最开始处。

【讨论】:

  • 谢谢@Oscar,但是在这种情况下如何使用锁?
  • 一个简单的锁将由类级别的static object screenLock; 组成,然后是要锁定的代码周围的lock(screenLock) {...}。当然,这可能会导致死锁,因为它在获取锁时不会超时。
  • 你能用锁修改我的代码吗?我已经了解如何锁定方法。
  • @Oscar,我已经尝试过您的代码,但我收到此错误:dropbox.com/s/b5dnyz6re20zygf/argumentException2.JPG
  • 抱歉,无法从我当前的位置访问 Dropbox :-(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多