C# 什么是警告线程停止运行的正确步骤';他在做什么,在离开前返回?
在退出应用程序之前,警告正在运行的线程停止正在执行的操作并返回的正确过程是什么C# 什么是警告线程停止运行的正确步骤';他在做什么,在离开前返回?,c#,.net,multithreading,winforms,C#,.net,Multithreading,Winforms,在退出应用程序之前,警告正在运行的线程停止正在执行的操作并返回的正确过程是什么 protected Thread T; protected static ManualResetEvent mre = new ManualResetEvent(false); protected static bool ThreadRunning = true; public Form1() { InitializeComponent(); T = new Thread(ThreadFunc);
protected Thread T;
protected static ManualResetEvent mre = new ManualResetEvent(false);
protected static bool ThreadRunning = true;
public Form1()
{
InitializeComponent();
T = new Thread(ThreadFunc);
T.Start();
}
private void ThreadFunc()
{
while (ThreadRunning)
{
// Do stuff
Thread.Sleep(40);
}
mre.Set();
}
private void ExitButton_Click(object sender, EventArgs e)
{
ThreadRunning = false;
mre.WaitOne();
mre.Close();
Application.Exit();
}
最初,我的代码设置与上面一样。我对如何正确退出的思考如下:
ThreadRunning=false
,以便下次线程T检查该变量时知道停止mre.WaitOne()
,等待线程T通过调用mre.Set()
表示它实际上已经完成了mre.Close()
)并退出mre.Set()
不会等待任何东西,而Application.Exit()
紧跟其后。我只是在等待它像以前一样失败,但到目前为止还没有
protected Thread T;
protected static ManualResetEvent mre = new ManualResetEvent(false);
protected static bool ThreadRunning = true;
public Form1()
{
InitializeComponent();
T = new Thread(ThreadFunc);
T.Start();
}
private void ThreadFunc()
{
while (ThreadRunning)
{
// Do stuff
Thread.Sleep(40);
}
mre.WaitOne();
mre.Close();
}
private void ExitButton_Click(object sender, EventArgs e)
{
ThreadRunning = false;
mre.Set();
Application.Exit();
}
使用
Thread.IsAlive
可以使用相同的条件变量模式,如下所示:
using System;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsAppTest
{
public partial class FormTest : Form
{
static volatile protected bool CancelRequired = false;
protected Thread TheThread;
使用
Thread.IsAlive
可以使用相同的条件变量模式,如下所示:
using System;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsAppTest
{
public partial class FormTest : Form
{
static volatile protected bool CancelRequired = false;
protected Thread TheThread;
UI挂起,因为您使用
mre.WaitOne()阻塞UI线程代码>。
如果需要等待线程退出,则可以使用其属性并处理应用程序消息,而不需要应用程序事件:
while(_t.IsAlive)
Application.DoEvents();
有两种线程取消方法:
- -线程执行的代码知道它可以被取消,并且可以优雅地处理取消,这就是您在这里尝试做的
- 命令式-强制线程停止-调用
线程。中止
或中断
,即
正如@HansPassant所提到的,bool
并不是最好的选择,因为编译器可能会对其进行优化,bool值可以缓存,其更改可能不会通过循环线程来处理。您需要使其至少易失性
,或者只需重构代码即可使用取消源代码
考虑到你的线程在做什么,也许BackgroundWorker
,Timer
或Producer/Consumer模式是线程
的更好的替代方案,但我没有太多的上下文来推荐任何东西。此外,只有当应用程序中只有一个Form1
实例时,它才能正常工作;如果您有多种形式的应用程序,并且用户可以打开多个Form1
表单,则会出现问题
一般建议,如果您可以使用实例级字段,请这样做,不要使用静态。UI挂起,因为您使用mre.WaitOne()阻塞UI线程代码>。
如果需要等待线程退出,则可以使用其属性并处理应用程序消息,而不需要应用程序事件:
while(_t.IsAlive)
Application.DoEvents();
有两种线程取消方法:
- -线程执行的代码知道它可以被取消,并且可以优雅地处理取消,这就是您在这里尝试做的
- 命令式-强制线程停止-调用
线程。中止
或中断
,即
正如@HansPassant所提到的,bool
并不是最好的选择,因为编译器可能会对其进行优化,bool值可以缓存,其更改可能不会通过循环线程来处理。您需要使其至少易失性
,或者只需重构代码即可使用取消源代码
考虑到你的线程在做什么,也许BackgroundWorker
,Timer
或Producer/Consumer模式是线程
的更好的替代方案,但我没有太多的上下文来推荐任何东西。此外,只有当应用程序中只有一个Form1
实例时,它才能正常工作;如果您有多种形式的应用程序,并且用户可以打开多个Form1
表单,则会出现问题
一般建议,如果您可以使用实例级字段,请这样做,不要使用静态。在两次操作之间等待40毫秒不会产生任何问题,但如果您必须等待5秒或更长时间怎么办?那么在每次等待之间取消将是有问题的,正确的做法是取消等待本身。实际上做这件事相当容易。只需将Thread.Sleep(40)
替换为Task.Delay(40,token.Wait()
,其中token
是一个
就我个人而言,我更喜欢使用任务
而不是线程
,因为它更容易等待而不会阻塞UI。此任务将使用线程池线程延迟运行。缺点是每40毫秒运行一次的东西并不总是在同一个线程中运行,因此我可能需要解决线程安全问题
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Task _task;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_task = Task.Run(TaskFunc);
this.FormClosing += Form_FormClosing;
}
private async Task TaskFunc()
{
try
{
while (true)
{
// Do async stuff here, using _cts.Token if possible
// The stuff will run in thread-pool threads
await Task.Delay(40, _cts.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private async void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_task == null || _task.IsCompleted) return;
e.Cancel = true;
_cts.Cancel();
this.Visible = false; // Or give feedback that the form is closing
var completedTask = await Task.WhenAny(_task, Task.Delay(5000));
if (completedTask != _task) Debug.WriteLine("Task refuses to die");
_task = null;
await Task.Yield(); // To ensure that Close won't be called synchronously
this.Close(); // After await we are back in the UI thread
}
}
在两次操作之间等待40毫秒不会产生任何问题,但如果您必须等待5秒或更长时间怎么办?那么在每次等待之间取消将是有问题的,正确的做法是取消等待本身。实际上做这件事相当容易。只需将Thread.Sleep(40)
替换为Task.Delay(40,token.Wait()
,其中token
是一个
就我个人而言,我更喜欢使用任务
而不是线程
,因为它更容易等待而不会阻塞UI。此任务将使用线程池线程延迟运行。缺点是每40毫秒运行一次的东西并不总是在同一个线程中运行,因此我可能需要解决线程安全问题
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Task _task;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_task = Task.Run(TaskFunc);
this.FormClosing += Form_FormClosing;
}
private async Task TaskFunc()
{
try
{
while (true)
{
// Do async stuff here, using _cts.Token if possible
// The stuff will run in thread-pool threads
await Task.Delay(40, _cts.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private async void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_task == null || _task.IsCompleted) return;
e.Cancel = true;
_cts.Cancel();
this.Visible = false; // Or give feedback that the form is closing
var completedTask = await Task.WhenAny(_task, Task.Delay(5000));
if (completedTask != _task) Debug.WriteLine("Task refuses to die");
_task = null;
await Task.Yield(); // To ensure that Close won't be called synchronously
this.Close(); // After await we are back in the UI thread
}
}
new Thread
用于启动和忘记线程,您不会取消这些线程,也不会从中获取信息,甚至不会关心它们是否正在运行。如果您想获取信息或取消您应该使用的线程,请查看此处。在最后一个回答中,您的问题回答了bool不是线程同步对象,如ManualResetEvent。“某些情况”是应用程序的发布版本,允许
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Thread _thread;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_thread = new Thread(ThreadFunc);
_thread.Start();
}
private void ThreadFunc()
{
try
{
while (true)
{
// Do stuff here
Task.Delay(40, _cts.Token).GetAwaiter().GetResult();
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
_cts.Cancel();
this.Visible = false; // Hide the form before blocking the UI
_thread.Join(5000); // Wait the thread to finish, but no more than 5 sec
this.Close();
}
}
class Form1 : Form
{
protected readonly CancellationTokenSource _cts;
protected readonly Task _task;
public Form1()
{
InitializeComponent();
_cts = new CancellationTokenSource();
_task = Task.Run(TaskFunc);
this.FormClosing += Form_FormClosing;
}
private async Task TaskFunc()
{
try
{
while (true)
{
// Do async stuff here, using _cts.Token if possible
// The stuff will run in thread-pool threads
await Task.Delay(40, _cts.Token).ConfigureAwait(false);
}
}
catch (OperationCanceledException)
{
// Ignore cancellation exception
}
}
private void ExitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private async void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_task == null || _task.IsCompleted) return;
e.Cancel = true;
_cts.Cancel();
this.Visible = false; // Or give feedback that the form is closing
var completedTask = await Task.WhenAny(_task, Task.Delay(5000));
if (completedTask != _task) Debug.WriteLine("Task refuses to die");
_task = null;
await Task.Yield(); // To ensure that Close won't be called synchronously
this.Close(); // After await we are back in the UI thread
}
}