为什么我的线程变成死锁c#

本文关键字:死锁 我的 线程 为什么 | 更新日期: 2023-09-27 18:06:48

我在一个应用程序中遇到了多线程问题。

流程基本上包括需要处理的项目列表。作为此处理的一部分,需要调用不支持多线程的第三方api。

我试图引入API类的单例实例,并使用锁定来确保一次只有一个线程调用它,但我仍然遇到这样的情况:一个线程在调用API时卡住了,而其他线程则卡住了,等待锁被释放。

如果我暂停调试会话并检查线程的调用堆栈,则对API调用进行调用的线程有以下跟踪:

mscorlib.dll ! System.Threading.WaitHandle.WaitAll (System.Threading。waitthandle [] waitthandle, int毫秒超时,bool退出上下文
mscorlib.dll ! System.Threading.WaitHandle.WaitAll (System.Threading。waitthandle [] waitthandles)

我已经在单个线程上测试了这一点,通过显式调用Process方法交换foreach循环中的线程池,它工作得很好(尽管比我想要的慢,在API调用之前和之后有相当多的处理)。

是我在这里做错了什么,还是这是第三方api的问题?

  public class MyClass
  {
     private static ThirdPartyApi ApiInstance;
     private static object lockObject = new object();
     ...
     public void DoWork(list)
     {
        ...
        foreach (var item in list)
        {
            ThreadPool.QueueUserWorkItem(Process, item);
        }   
        ...
      }

        public void Process(string item)
        {
             // Various processing
              ...
              lock(lockObject)
              {
                  var result = ApiInstance.Lookup(item);
              }
              ...
         }

为什么我的线程变成死锁c#

线程不安全的代码并不一定意味着方法不可重入,一些线程不安全的库要求所有调用来自同一个线程,就这样。试试下面使用BlockingCollection的方法,它将在同一个线程上发出所有调用,看看它是否解决了这个问题。

public class MyClass<T>
{
    private BlockingCollection<T> workQueue = new BlockingCollection<T>();
    public MyClass()
    {
        Task.Factory.StartNew(ProcessWorkQueue, TaskCreationOptions.LongRunning);
    }
    public void DoWork(List<T> work)
    {
        foreach (var workItem in work)
        {
            workQueue.Add(workItem);
        }
    }
    public void StopWork()
    {
        workQueue.CompleteAdding();
    }
    public void ProcessWorkQueue()
    {
        foreach(var item in workQueue.GetConsumingEnumerable())
        {
            //Do something here
        }
    }
}

同样,ThreadPool是一个共享资源,对ThreadPool线程执行任何阻塞操作都会耗尽它。即使您的代码可以正常工作,也需要对其进行重构以解决这个资源匮乏问题。