信号量锁导致死锁

时间:2021-02-05 04:35:55

标签: c# .net multithreading task

public class SampleData
{
 private static readonly Semaphore pool = new Semaphore(0,1);

 public string Data => getFromFile();

 private static string getFromFile()
 {
   pool.WaitOne();
   var data = 
   File.ReadAllText("somefilepath");
    pool.Release();
    return data;
  }
}

在 program.cs 中

var tasks = new List<Task<string>>();
for(int i=0; i<=5; i++)
{
   tasks.Add(Task.Run<string>(()=> 
    new SampleData().Data));
}

Task.WaitAll(tasks.ToArray());

当我运行它时,它永远不会完成任务。谁能告诉我这里有什么问题?

谢谢。

2 个答案:

答案 0 :(得分:0)

如果 getFromFile() 抛出异常,信号量将永远不会被释放并且 Task.WaitAll 将永远等待,您需要将 pool.Release() 移动到 finally 部分。这可能就是无限期等待的原因。

private static string getFromFile()
 {
   pool.WaitOne();
   try {
     var data = File.ReadAllText("somefilepath");
     return data;
   }
   finally {
     pool.Release();
   }
  }
}

答案 1 :(得分:0)

首先

如果这不是跨进程,您应该考虑使用 SemaphoreSlim

其次

关于您对 Semaphore(0,1) 的初始化。如果 initialCount 小于 maximumCount,效果与当前线程调用 WaitOne (maximumCount 减去 initialCount) 次一样。

也就是说,当您在当前配置中调用 pool.WaitOne(); 时,您将一直阻塞,直到有人调用 release(直接)。

例如:

private static readonly Semaphore pool = new Semaphore(0,1);

static void Main(string[] args)
{
   pool.WaitOne();
   Console.WriteLine("This will never get executed");
}

您可能想要:

Semaphore(1,1)
// or
SemaphoreSlim(1,1)

最后

您必须始终将这些同步原语包装在try finally中,否则您最终会在异常时死锁Release 之前被抛出。

SemaphoreSlim

await pool.WaitAsync();
try
{
   // do something
}
finally
{
   pool.Release();
}

或者如果你真的需要使用 Semaphore

pool.WaitOne();
try
{

  // do something
}
finally
{
   pool.Release();
}
相关问题