简体   繁体   中英

Invoke Method never returns

I have a thread running, which grabs images from a camera, saves them, and updates the pictureBox to display that bitmap. When I want to exit the application, I set my bool exitApplication to true, but it never returns on the join() call.

    public void GrabThread()
    {
        Bitmap copyBmp;
        while (!exitApplication)
        {
            mImage = m_camera.GrabImage();
            SaveImage();

            copyBmp = (Bitmap)mImage.bmp.Clone();
            if (pictureBox1.InvokeRequired)
            {
                pictureBox1.Invoke(new MethodInvoker(
                delegate ()
                {
                    pictureBox1.Image = copyBmp;
                }));
            }
            else
            {
                pictureBox1.Image = copyBmp;
            }
            m_camera.ReleaseImage();
        }
    }

My Exit code:

        exitApplication = true;
        threadGrab.Join();
        m_camera.Stop();
        Close();

When I call Break All from the Debug menu, the Thread hangs at

pictureBox1.Invoke(new MethodInvoker(
delegate ()
{
    pictureBox1.Image = copyBmp;
}));

Why? And how can I prevent this? Currently I have to call Abort() on the thread to exit it.

This code deadlocks because pictureBox1.Invoke is trying to execute code in the UI thread. That thread though is blocked by the call to threadGrab.Join();

This can be fixed using async/await . await awaits already executing asynchronous tasks without blocking the way Join() does. When it finishes, execution resumes in the original synchronization context. In a WinForms or WPF application, this means execution resumes on the UI thread.

I assume the only thing that needs to run in the background is m_camera.GrabImage(); . In that case, the code could look something like this :

public async void Button1_Click(object sender, EventArgs args)
{
    await Task.Run(()=>m_camera.GrabImage();
    //Back in the UI thread
    SaveImage();
    var copyBmp = (Bitmap)mImage.bmp.Clone();
    pictureBox1.Image = copyBmp;
    m_camera.ReleaseImage();
}

Task.Run will execute m_camera.GrabImage() in a threadpool thread. await will await for this to finish without blocking the UI thread. When it finishes, execution resumes in the UI thread which means there's no need for Invoke .

This could run in a loop too :

public async void Capture_Click(object sender, EventArgs args)
{
    while(someCondition)
    {
        await Task.Run(()=>m_camera.GrabImage();

        SaveImage();
        var copyBmp = (Bitmap)mImage.bmp.Clone();
        pictureBox1.Image = copyBmp;
        m_camera.ReleaseImage();
    }
}

It may not the right answer but you can using both OnClosing and OnClosed to Stop your camera then close your app, I don't know does it work in Winform but it worked with me in WPF

protected override void OnClosing(CancelEventArgs e)
{

            e.Cancel = false; //prevent your application to shutdown
            Camera.Stop(); //stop your camera
            base.OnClosing(e);

}

protected override void OnClosed(EventArgs e)
{
            base.OnClosed(e);
            Application.Current.Shutdown(); //then shutdown again
}

Via 2 step, your camera will stop without Join any thread. And note that this code is written in Wpf, not Winform but I thought you can find a similar way to do in Winform

Hope this answer may help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM