Метод Invoke никогда не возвращается - PullRequest
0 голосов
/ 03 июля 2019

У меня запущен поток, который берет изображения с камеры, сохраняет их и обновляет pictureBox для отображения этого растрового изображения.Когда я хочу выйти из приложения, я устанавливаю для моего bool exitApplication значение true, но оно никогда не возвращается при вызове join().

    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();
        }
    }

Мой код выхода:

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

Когда я вызываю Break All из меню отладки, поток зависает на

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

Почему?И как я могу предотвратить это?В настоящее время я должен вызвать Abort () в потоке, чтобы выйти из него.

Ответы [ 2 ]

1 голос
/ 03 июля 2019

Этот код блокируется, потому что pictureBox1.Invoke пытается выполнить код в потоке пользовательского интерфейса.Этот поток заблокирован вызовом threadGrab.Join();

. Это можно исправить с помощью async/await.await ожидает выполнения асинхронных задач без блокировки, как Join().Когда он заканчивается, выполнение возобновляется в исходном контексте синхронизации.В приложениях WinForms или WPF это означает, что выполнение возобновляется в потоке пользовательского интерфейса.

Полагаю, единственное, что нужно запустить в фоновом режиме, - это m_camera.GrabImage();.В этом случае код может выглядеть примерно так:

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 выполнит m_camera.GrabImage() в потоке потоков.await будет ожидать завершения этой операции без блокировки потока пользовательского интерфейса.Когда он заканчивается, выполнение возобновляется в потоке пользовательского интерфейса, что означает, что Invoke.

не требуется. Это также может выполняться в цикле:

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();
    }
}
0 голосов
/ 03 июля 2019

Возможно, это не правильный ответ, но вы можете использовать OnClosing и OnClosed для остановки камеры и закрытия приложения. Я не знаю, работает ли она в Winform, но она работала со мной в 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
}

Через 2 шага ваша камера остановится без присоединения к какой-либо теме.И обратите внимание, что этот код написан на Wpf, а не на Winform, но я подумал, что вы можете найти аналогичный способ сделать в Winform

Надеюсь, этот ответ может вам помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...