C# WinForms中的线程锁

C# WinForms中的线程锁,c#,.net,multithreading,winforms,deadlock,C#,.net,Multithreading,Winforms,Deadlock,我有一个类,它在线程中生成图像,并在每一帧上调用一个事件。表单订阅此事件,并使用调用在图片框中显示图像 如果允许图像生成过程完成,则一切正常。但是,如果窗体在线程运行时关闭,则窗体会尝试停止线程,但最终会导致某种死锁 当我尝试在没有表单的情况下使用threaded类时,或者在控制台中使用应用程序时,启动该过程,等待一秒钟,然后取消它,一切正常 问题是,Form的Form\u Closing方法或threaded类的Stop方法肯定有问题 我将代码保持在最低限度,可以将其粘贴到LinqPad等中

我有一个类,它在线程中生成图像,并在每一帧上调用一个事件。
表单
订阅此事件,并使用
调用
图片框
中显示图像

如果允许图像生成过程完成,则一切正常。但是,如果
窗体
在线程运行时关闭,则
窗体
会尝试停止线程,但最终会导致某种死锁

当我尝试在没有
表单的情况下使用threaded类时,或者在
控制台中使用
应用程序时,启动该过程,等待一秒钟,然后
取消
它,一切正常

问题是,
Form
Form\u Closing
方法或threaded类的
Stop
方法肯定有问题

我将代码保持在最低限度,可以将其粘贴到LinqPad等中

一个辅助问题:
Process
方法是否应该调用
Stop
方法进行清理

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

namespace VideoMask.WinFormsAppApp
{
    internal static class Program
    {
        [STAThread]
        private static void Main ()
        {
            Program.TestWithoutForm(); // Runs fine.
            Program.TestWithForm(); // Deadlocks.
        }

        private static void TestWithForm ()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new FormMain());
        }

        private static void TestWithoutForm ()
        {
            new TestWithoutForm().Run();
        }
    }

    public class TestWithoutForm
    {
        private VideoProcessor VideoProcessor = new VideoProcessor();

        public TestWithoutForm ()
        {
            this.VideoProcessor.SourceFrameRead += this.VideoProcessor_SourceFrameRead;
        }

        public void Run ()
        {
            this.VideoProcessor.Start();
            Thread.Sleep(1000);
            this.VideoProcessor.Stop();

            MessageBox.Show("Done");
        }

        private void VideoProcessor_SourceFrameRead (object sender, VideoProcessorEventArgs e)
        {
            var filename = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Sample.png");

            e.Bitmap.Save(filename, ImageFormat.Png);
        }
    }


    public class FormMain: Form
    {
        private PictureBox PictureBox = new PictureBox();
        private VideoProcessor VideoProcessor = new VideoProcessor();

        public FormMain ()
        {
            this.Controls.Add(this.PictureBox);
            this.PictureBox.Dock = DockStyle.Fill;

            this.Shown += this.FormMain_Shown;
            this.FormClosing += this.FormMain_FormClosing;

            this.WindowState = FormWindowState.Maximized;
        }

        private void FormMain_Shown (object sender, EventArgs e)
        {
            this.VideoProcessor.SourceFrameRead += this.VideoProcessor_SourceFrameRead;
            this.VideoProcessor.Start();
        }

        private void FormMain_FormClosing (object sender, FormClosingEventArgs e)
        {
            this.VideoProcessor.Stop();
            this.VideoProcessor.Dispose();
            this.VideoProcessor = null;
        }

        private void VideoProcessor_SourceFrameRead (object sender, VideoProcessorEventArgs e)
        {
            this.Invoke
            (
                new Action
                (
                    () =>
                    {
                        using (var bitmap = this.PictureBox.Image)
                        {
                            this.PictureBox.Image = new Bitmap(e.Bitmap);
                        }
                    }
                )
            );
        }
    }

    public sealed class VideoProcessor: IDisposable
    {
        public event EventHandler<ErrorEventArgs> ConversionError = null;
        public event EventHandler<VideoProcessorEventArgs> SourceFrameRead = null;

        private Font Font = null;
        private Bitmap Bitmap = null;
        private Thread Thread = null;
        private Graphics Graphics = null;
        private readonly object SyncRoot = new object();
        private CancellationTokenSource CancellationTokenSource = null;

        public VideoProcessor ()
        {
            this.Bitmap = new Bitmap(800, 600, PixelFormat.Format32bppArgb);
            this.Graphics = Graphics.FromImage(this.Bitmap);
            this.Font = new Font(FontFamily.GenericSansSerif, 48, GraphicsUnit.Point);
        }

        public bool IsRunning { get; private set; }

        public void Start ()
        {
            lock (this.SyncRoot)
            {
                if (this.IsRunning) { throw (new Exception("A video conversion process is already running.")); }

                this.Stop();
                this.CancellationTokenSource = new CancellationTokenSource();
                this.Thread = new Thread(new ParameterizedThreadStart(this.Process));
                this.Thread.Start(this.CancellationTokenSource);
            }
        }

        public void Stop ()
        {
            lock (this.SyncRoot)
            {
                if (!this.IsRunning) { return; }

                this.CancellationTokenSource?.Cancel();

                this.Thread.Join();

                this.Thread = null;
                this.CancellationTokenSource?.Dispose();
                this.CancellationTokenSource = null;
            }
        }

        private void Process (object cancellationTokenSource)
        {
            var source = (CancellationTokenSource) cancellationTokenSource ?? throw (new ArgumentNullException(nameof(cancellationTokenSource)));

            lock (this.SyncRoot) { if (this.IsRunning) { throw (new Exception("A conversion process is already running.")); } }

            this.IsRunning = true;

            for (var i = 1; i <= int.MaxValue; i++)
            {
                if (source.IsCancellationRequested) { break; }

                this.Graphics.Clear(Color.White);
                this.Graphics.DrawString(i.ToString(), this.Font, Brushes.Black, 10, 10);
                this.SourceFrameRead?.Invoke(this, new VideoProcessorEventArgs(this.Bitmap));

                Thread.Sleep(33);
            }

            this.IsRunning = false;
        }

        public void Dispose () => this.Stop();
    }

    public class VideoProcessorEventArgs: EventArgs
    {
        public Bitmap Bitmap { get; private set; }
        public VideoProcessorEventArgs (Bitmap bitmap) { this.Bitmap = bitmap; }
    }
}
使用系统;
使用系统图;
使用系统、绘图、成像;
使用System.IO;
运用系统反思;
使用系统线程;
使用System.Windows.Forms;
命名空间VideoMask.WinFormsApp
{
内部静态类程序
{
[状态线程]
私有静态void Main()
{
Program.TestWithoutForm();//运行正常。
Program.TestWithForm();//死锁。
}
私有静态void TestWithForm()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
运行(newformmain());
}
私有静态void TestWithoutForm()
{
新的TestWithoutForm().Run();
}
}
不带表单的公共类测试
{
专用视频处理器VideoProcessor=新的视频处理器();
不带表单的公共测试()
{
this.VideoProcessor.SourceFrameRead+=this.VideoProcessor\u SourceFrameRead;
}
公开作废运行()
{
这是.VideoProcessor.Start();
睡眠(1000);
这个.VideoProcessor.Stop();
MessageBox.Show(“完成”);
}
私有void视频处理器\u SourceFrameRead(对象发送器、视频处理器或ventargs e)
{
var filename=Path.Combine(Path.GetDirectoryName(Assembly.getExecutionGassembly().Location),“Sample.png”);
e、 保存(文件名,ImageFormat.Png);
}
}
公共类FormMain:Form
{
私有PictureBox PictureBox=新PictureBox();
专用视频处理器VideoProcessor=新的视频处理器();
公共FormMain()
{
this.Controls.Add(this.PictureBox);
this.PictureBox.Dock=DockStyle.Fill;
this.show+=this.FormMain_show;
this.FormClosing+=this.FormMain\u FormClosing;
this.WindowState=FormWindowState.Maximized;
}
显示私有void FormMain_(对象发送方,事件参数e)
{
this.VideoProcessor.SourceFrameRead+=this.VideoProcessor\u SourceFrameRead;
这是.VideoProcessor.Start();
}
私有void FormMain\u FormClosing(对象发送方,FormClosingEventArgs e)
{
这个.VideoProcessor.Stop();
这个.VideoProcessor.Dispose();
this.VideoProcessor=null;
}
私有void视频处理器\u SourceFrameRead(对象发送器、视频处理器或ventargs e)
{
这个,调用
(
新行动
(
() =>
{
使用(var bitmap=this.PictureBox.Image)
{
this.PictureBox.Image=新位图(例如位图);
}
}
)
);
}
}
公共密封类视频处理器:IDisposable
{
公共事件事件处理程序ConversionError=null;
公共事件EventHandler SourceFrameRead=null;
私有字体=null;
私有位图=空;
私有线程线程=null;
私有图形=空;
私有只读对象SyncRoot=新对象();
private CancellationTokenSource CancellationTokenSource=null;
公共视频处理器()
{
this.Bitmap=新位图(800600,PixelFormat.Format32bppArgb);
this.Graphics=Graphics.FromImage(this.Bitmap);
this.Font=新字体(FontFamily.GenericSansSerif,48,GraphicsUnit.Point);
}
公共bool正在运行{get;private set;}
公共无效开始()
{
锁定(this.SyncRoot)
{
if(this.IsRunning){抛出(新异常(“视频转换进程已在运行”);}
这个。停止();
this.CancellationTokenSource=新的CancellationTokenSource();
this.Thread=新线程(新参数化的threadstart(this.Process));
this.Thread.Start(this.CancellationTokenSource);
}
}
公众停车场()
{
锁定(this.SyncRoot)
{
如果(!this.IsRunning){return;}
此.CancellationTokenSource?.Cancel();
this.Thread.Join();
this.Thread=null;
此.CancellationTokenSource?.Dispose();
this.CancellationTokenSource=null;
}
}
私有无效进程(对象cancellationTokenSource)
{
var source=(CancellationTokenSource)CancellationTokenSource??抛出(新参数NullException(nameof(CancellationTokenSource));
lock(this.SyncRoot){if(this.IsRunning){抛出(新异常(“转换进程已在运行”);}
这是伊斯鲁尼