【问题标题】:Why do my threads become deadlocked C#?为什么我的线程会死锁 C#?
【发布时间】:2014-06-04 19:04:37
【问题描述】:

我目前正在处理的应用程序中的多线程存在问题。

该过程基本上涉及需要处理的项目列表。作为此处理的一部分,需要调用不支持多线程的第 3 方 API。

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

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

mscorlib.dll!System.Threading.WaitHandle.WaitAll(System.Threading.WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext)
mscorlib.dll!System.Threading.WaitHandle.WaitAll(System.Threading.WaitHandle[] waitHandles)

我已经通过显式调用 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);
              }
              ...
         }

【问题讨论】:

  • 你的 lockObject 是从哪里来的?
  • 另外,ThirdPartyApi 是否声称是线程安全的? MyClass 是 ThirdPartyApi 的唯一合作者吗?
  • 您说“作为此处理的一部分,需要调用不支持多线程的第 3 方 api”那么,您为什么要尝试这样做那么呢?
  • lockObject 是类中的静态对象,仅用于控制对 API 的访问。我不确定 ThirdPartyApi 是否应该是线程安全的,但这是唯一与它有任何交互的类。对 API 的实际调用非常快(
  • 您是否在代码的任何其他部分修改或使用 lockObject?

标签: c# multithreading threadpool


【解决方案1】:

线程不安全的代码并不一定意味着方法不可重入,一些线程不安全的库要求所有调用都来自同一个线程,句号。改用 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 线程执行任何阻塞操作都会耗尽它。即使您的代码确实有效,也需要对其进行重构以解决此资源匮乏问题。

【讨论】:

    猜你喜欢
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多