C# 在';使用';块处理已用实例
我正在开始这样一个线程:C# 在';使用';块处理已用实例,c#,multithreading,C#,Multithreading,我正在开始这样一个线程: nameOfThread = new Thread(() => { //do stuff }); nameOfThread.Start(); using (Session session = new Session()) { //do stuff } 在这个匿名函数中的某个时刻,我打开了一个WinSCP会话,如下所示: nameOfThread = new Thread(() => { //do stuff }); name
nameOfThread = new Thread(() =>
{
//do stuff
});
nameOfThread.Start();
using (Session session = new Session())
{
//do stuff
}
在这个匿名函数中的某个时刻,我打开了一个WinSCP会话,如下所示:
nameOfThread = new Thread(() =>
{
//do stuff
});
nameOfThread.Start();
using (Session session = new Session())
{
//do stuff
}
如果我像这样中止线程(从其他地方)nameOfThread.abort()
根据文件:
在线程上调用此方法[Abort
]时,系统会在线程中抛出ThreadAbortException
,以中止该方法
我们知道,异常仍然会让使用语句进行处理,这是它们应该做的。(给出并接受一些例外情况)
另一方面,如果您可以优雅地结束线程,例如使用CancellationTokenSource
,那么对您的应用程序来说会更好。它将提供对线程的实际终止和异常处理的更多控制。我回答说,您可以保证using
语句将始终调用Dispose
,并且我得到纠正,我错了
有一个潜在的竞争条件,即使用的
语句不能保证处置,我已经编写了一个控制台应用程序来说明这一点(这不是很难或很琐碎)
我正确地展示了IL如何使用
生成,如下所示:
var session = new Session(); //If this causes an error or abort happens during initialization then we don't enter try
//If abort is called here then we never enter try
//In either case above we may have undisposed resources initialized at this point
try
{
//do stuff
}
finally
{
session.Dispose();
}
但是,;请注意我在其中显示的注释,如果在进入try
之前中止,可能会发生竞态条件
下面是一个控制台应用程序,旨在证明这一点。第一个按预期工作,但如果您在初始化R
时添加注释掉的代码//thread.Abort()
,则您将看到它init,但不会dispose:/
using System;
using System.Threading;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Start Main");
Thread thread = null;
thread = new Thread(new ThreadStart(() =>
{
Console.WriteLine("Thread Started");
using (var r = new R(thread))
{
Console.WriteLine($"Using {nameof(R)}");
}
}));
thread.Start();
thread.Join();
Console.WriteLine("End Main");
Console.ReadKey();
}
}
public class R : IDisposable
{
public R(Thread thread)
{
Console.WriteLine($"Init {nameof(R)}");
//thread.Abort();
}
public void Dispose()
{
Console.WriteLine($"Disposed {nameof(R)}");
}
}
}
用//thread.Abort()输出注释掉:
Start Main
Thread Started
Init R
Using R
Disposed R
End Main
Start Main
Thread Started
Init R
End Main
带有线程的输出。中止()
未注释掉:
Start Main
Thread Started
Init R
Using R
Disposed R
End Main
Start Main
Thread Started
Init R
End Main
为什么中止线程?使用CancellationTokenSource并优雅地向worker方法发出信号,表示它需要终止眼睛,无论是否中止,using
语句仍能正确处理。为什么要直接使用线程而不是例如Task.Run?如果您有问题并认为thread.Abort
是解决方案的一部分,你找到了错误的解决方案。请注意@PanagiotisKanavos中的警告,因为在多线程方面,我并不是一个真正的专家。但这并不能回答问题好吧,谢谢你的回答和选择。我将进一步研究多线程。请记住,线程可以调用ResetAbort
,并防止ThreadAbortException
的影响。您将在中找到不方便的事实。@HansPassant这应该不再是真的。我记得读过的.NET的早期版本解决了这个问题,不确定是哪个版本,现在try/finally
嵌套在另一个try/finally
中,由其他线程管理来处理。不要混淆OP,但这是一个幕后工作,以确保这种情况不再发生。照现在的情况看,在当前的.NET版本中,没有竞争条件的情况下,应该以准确和线程安全的方式解决。我必须回过头来看看这是什么时候更新的。这是一个有趣的小道消息,值得更好的注释,因为这在我的.NET 4.7.2和C#v7.3中的机器上还没有发生。我认为问题不在于如何使用工作,而在于线程中止如何对其产生影响。@Patrickhoffman你是对的。也许我应该解释得更好,但我确实提到了一个线程,即使被中止,也总是调用finally
,因为它基本上被翻译成try finally
,所以在中止时它会被处理。@Patrickhoffman我更新了底部的答案,希望能让它更清楚。