代码之家  ›  专栏  ›  技术社区  ›  Codejoy

如何线程安全调用PictureBox.图像在c#中,当前给出3个错误中的一个

  •  2
  • Codejoy  · 技术社区  · 14 年前

    我在表单上使用这个图片框,在这个图片框中我使用了一个forge代码。我将pictureBox的引用传递到我创建的webcam类中,该类初始化webcam并告诉它在何处绘制帧…因此它很高兴地绘制帧。。。没问题。

    但在某些时候(当我想对所说的图像进行处理时,如果单击了一个chck框)……我用简单的代码启动这个计时器:

    timer1.Enabled = true;
    

    此计时器的间隔设置为33。

    所以现在它一直在发射,每次通过循环我的代码都有这样一个:

    private void timer1_Tick(object sender, EventArgs e)
    {
        ...
        double value = detector.ProcessFrame(new Bitmap(picCapture.Image)); //errors here
        ...
    
            TimerCallback tc = new TimerCallback(sendDataFast);
            System.Threading.Timer t = new System.Threading.Timer(tc, null, 2000, Timeout.Infinite);
    
    }
    

    上面那行有我在上面看到的三个错误之一(堆栈跟踪,如果可用):

    Object is currently in use elsewhere.

    Out of Memory. (A first chance exception of type 'System.OutOfMemoryException' occurred in System.Drawing.dll)

    Parameter not valid (A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll)

    我在别的地方看到有人说可能是线程问题

    所以我在time1\u click方法的顶部做了,但是断言似乎没有发生,但是我不确定这是断言的正确位置。。。timer1\u是否在UI线程中单击?

    我怀疑现在我检查了我的代码,这与我初始化webcam类的方式有关:

    void sendDataFast(Object stateObject)
    {
        EmergencyDelegate delEmergency =
               new EmergencyDelegate(mic.sendDataEmergency);
    
        // call the BeginInvoke function! //sendDataEmergency takes in a picture Image picImage as an argument.
        delEmergency.BeginInvoke(picCapture.Image, null, null);
    }
    

    为了完整起见,我是这样初始化我的网络摄像头类的:

            webcam = new WebCam();
            webcam.InitializeWebCam(ref picCapture, ref picComparator, ref dataObject, this);            //guessing this is calling threading issues        
    

    发生的这三个错误不会马上发生,似乎是随机发生的三个错误中的一个。。。。导致我认为这是一个线程问题,但我如何才能解决这个问题?出于某种原因创建一个委托,该委托返回双精度值并在invoke required为true时被调用?

    3 回复  |  直到 14 年前
        1
  •  3
  •   Community CDub    7 年前

    timer1\u是否在UI线程中单击?

    如果你看一下系统线程计时器您将看到以下内容

    系统线程计时器很简单, 线程。不建议使用 使用Windows窗体,因为 用户上不会发生回调 接口线程。 系统.Windows.Forms计时器是更好的选择 与Windows一起使用的选择表格.选择用于Windows窗体。

    这就是为什么你会冻僵。

    计时器应该是可重入的,因为它 在线程池线程上调用。这个 可以执行回调 同时在两个线程池上 如果计时器间隔小于 回调,或者如果所有线程池 线程正在使用中,回调正在进行 多次排队。

    这意味着如果你的函数在33毫秒内执行失败,函数将被再次调用。这可能就是你看到的例外情况的原因。两个或多个线程正在尝试使用同一个文件。您也可能有多个线程试图分配一大块内存,其中一个线程无法获得您请求的大小的块。不确定为什么会出现参数异常,但可能是因为前两个异常。

    因此我更喜欢系统计时器计时器. 它的AutoReset属性设置为false。然后在我的函数结束时,我调用计时器。开始. 你可以用其他计时器完成同样的事情,但这有点小把戏。

    这里有三个你可能会发现有用的链接

    Article on Comparison of the Timer Classes

    Jon Skeet Answer on a Begin Invoke Question

    Eric Lippert Blog on what an OutOfMemory Exception likely is

        2
  •  1
  •   Henk Holterman    14 年前

    我想当看到这条线

    double value = detector.ProcessFrame(new Bitmap(picCapture.Image)); 
    

    这是什么探测器.工艺框架你知道吗?

    3-为什么你要在滴答声事件中创建更多的计时器????

        3
  •  1
  •   tia    14 年前

    对于OutOfMemoryException,我建议替换

    double value = detector.ProcessFrame(new Bitmap(picCapture.Image));
    

    double value;
    using(Bitmap bmp = new Bitmap(picCapture.Image)) {
        value = detector.ProcessFrame(bmp);
    }