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){抛出(新异常(“转换进程已在运行”);}
这是伊斯鲁尼