【发布时间】:2021-02-22 12:08:15
【问题描述】:
Thread.Join 方法具有三个重载:Join()、Join(Int32) 和 Join(TimeSpan)。对于这三个重载中的每一个,都有以下语句in the Microsoft doc:
如果调用Join时线程已经终止,则该方法立即返回。
虽然此语句对 Join() 重载有意义,但它没有指定为 Join(Int32) 和 Join(TimeSpan) 返回哪个值,因此我在两个不同的环境中测试了 Int32 重载:
- Windows 10:返回 true
- Linux/Docker:返回 false(在 Docker 桌面上使用 mcr.microsoft.com/dotnet/runtime:5.0)
请注意,如果在调用 Join 时线程仍在运行并且在 称呼。如果线程在调用之前 终止,它只会返回 false。
在我看来,Join 无论在什么平台上都应该始终返回 true,那么如何解释这种不一致的行为呢?我错过了什么还是 .NET 5 错误?
更新
根据@txtechhelp 的建议,here is a .NET Fiddle 提供我正在测试的确切代码。
如果我在 Windows 10(或 .NET Fiddle)上运行此代码,我会得到以下结果:
Starting..
Sleeping 1200..expect T1 end before join
In T1
Leaving T1
Join(100)..expect success
Join(100) success!
Done..
然后,如果我在 Docker Desktop (v. 3.1.0) 上使用 mcr.microsoft.com/dotnet/runtime:5.0 运行此代码,则会得到以下结果:
Starting..
Sleeping 1200..expect T1 end before join
In T1
Leaving T1
Join(100)..expect success
Join(100) failed
Done..
更新 2
实际上,经过进一步测试后,我意识到只有在 Docker 应用程序正在卸载时调用Join(即接收到AssemblyLoadContext.Default.Unloading 事件后,即 Docker 发送的通知它的信号),上述测试才会失败将关闭应用程序)。
所以here is the exact test 甚至在.NET Fiddle 上都失败了:
public class Program
{
public static void Main()
{
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += (arg) => { OnStopSignalReceived("application unloading"); };
}
public static void T1()
{
System.Console.WriteLine("In T1");
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("Leaving T1");
}
private static void OnStopSignalReceived(string stopSignalSource)
{
System.Threading.Thread t1 = new System.Threading.Thread(T1);
System.Console.WriteLine("Starting..");
t1.Start();
System.Console.WriteLine("Sleeping 1200..expect T1 end before join");
System.Threading.Thread.Sleep(1200);
System.Console.WriteLine("Join(100)..expect success");
if (t1.Join(100))
{
System.Console.WriteLine("Join(100) success!");
}
else
{
System.Console.WriteLine("Join(100) failed");
}
t1.Join();
System.Console.WriteLine("Done..");
}
}
【问题讨论】:
-
也许它返回null?
-
@jdweng 我的问题确实是关于 int 或 TimeSpan 重载,它们返回一个不可为空的布尔值。我将编辑我的问题以进行澄清。
-
您链接的文档明确指出:如果线程终止,则返回 true;如果在 timeout 参数指定的时间量过后线程尚未终止,则返回 false。因此,如果线程终止,如果实现返回 false,我建议提交 Bug。
-
@Rem 建议在 GitHub 上的 dotnet/runtime repo 上提出这个问题,微软肯定会告诉你这是正确的还是错误的。
-
你能发布一些麻烦的代码吗?在多个平台(包括 Docker)上进行快速测试会产生预期的结果。这是我用来测试您声称的内容的 C# 代码:dotnetfiddle;如您所见,我专门尝试调用您所说的行为,其中线程退出 然后
Yield(Int32)被调用,而在 Linux 中您将获得false值(意思是线程尚未退出并且指定的时间跨度已通过)。相关代码将有助于确定问题所在,因为它似乎不可重现。
标签: c# multithreading .net-core