测试环境
可复制的代码:
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace SignalTest
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
{
new Thread(new ThreadStart(new Worker($"c{i % 3}", $"name{i}").Start)).Start();
}
Console.ReadKey();
}
}
class Worker
{
public static ConcurrentDictionary<string, Semaphore> Semaphores = new ConcurrentDictionary<string, Semaphore>();
public string Name { get; set; }
public string Code { get; set; }
public int Count { get; private set; }
public Worker(string code, string name)
{
Code = code;
Name = name;
Semaphores.TryAdd(Code, new Semaphore(1, 1));
}
public void Start()
{
while (true)
{
try
{
WriteLog($"[{Code}][{Name}] Wait.");
Semaphores[Code].WaitOne();
WriteLog($"[{Code}][{Name}] Begin.");
WriteLog($"[{Code}][{Name}] Working => {++Count}!!!");
Thread.Sleep(500);
}
finally
{
WriteLog($"[{Code}][{Name}] Release.");
Semaphores[Code].Release();
}
}
}
public void WriteLog(string msg)
{
if (Code == "c1")
Console.WriteLine(msg);
}
}
}
所需的输出应该是将所有c1-coded
线程打印为1,然后打印2,然后为3 ...,但是在dotnetcore 3.1(VS Debug实例,Debug> Start New Instance)中,结果可能不是您想要的,一个错误?不受欢迎的输出片段之一可能是:
[c1][name1] Working => 4!!!
[c1][name1] Release.
[c1][name1] Wait.
[c1][name4] Begin.
[c1][name4] Working => 4!!!
[c1][name4] Release.
[c1][name7] Begin.
[c1][name7] Working => 4!!!
[c1][name4] Wait.
[c1][name7] Release.
[c1][name7] Wait.
[c1][name10] Begin.
[c1][name10] Working => 2!!!
[c1][name10] Release.
[c1][name10] Wait.
[c1][name13] Begin.
[c1][name13] Working => 1!!!
[c1][name13] Release.
[c1][name13] Wait.
[c1][name16] Begin.
[c1][name16] Working => 1!!!
[c1][name16] Release.
[c1][name16] Wait.
[c1][name19] Begin.
[c1][name19] Working => 1!!!
最佳答案
如所有版本的Semaphore
(和SemaphoreSlim
)的documentation中所述,是否为.NET Core:
There is no guaranteed order, such as FIFO or LIFO, in which blocked threads enter the semaphore.
在您的示例中,假设
[name1]
输入了一个信号量,而所有其他线程都在等待。 [name1]
输出1,并递增计数器。然后,任何等待线程都可以不按特定顺序进入。说它是name2
。同时,name1
已被阻止等待互斥。 name2
pritns 1,递增计数器。现在要点-不能保证name1
在互斥体上等待再次输入,因为不能保证顺序。因此它进入,打印2,递增计数器。然后可以输入name3,并在该name1之后再次打印3,而其他线程仍为1。因此,您在完整的.net或没有调试器的情况下观察到的“正确”行为仅仅是快乐的巧合,这并不能保证会发生。因此,当它没有发生时-这不是错误。
关于c# - 在VS的 Debug模式下使用netcore 3.1时,线程无序地排队,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64801231/