简体   繁体   中英

Why do my threads become deadlocked C#?

I'm having problems with multi-threading in an application I'm working on at the minute.

The process basically involves a list of items which need to be processed. As part of this processing a call needs to be made to a 3rd party api which does not support multi threading.

I've attempted to introduce a singleton instance of the API class and use locking to ensure that only one thread makes a call to it at once but I still get a situation were one thread gets stuck on the call to the API and the others are then stuck waiting on the lock to be released.

If I pause the debug session and check the callstack for the threads the one that has made it to the API call has the following trace:

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

I've tested this on a single thread by swapping out the thread pool in the foreach loop with an explicit call to the Process method and it works fine (although slower than I would like, there is quite a lot of processing before and after the API call).

Am I doing something wrong here or is this an issue with the third party 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);
              }
              ...
         }

Code that is thread unsafe doesn't necessarily mean that the methods are not re-entrant, some thread-unsafe libraries require all calls to come from the same thread, period. Try the following method using a BlockingCollection instead, which will issue all calls on the same thread and see if it resolves the issue.

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
        }
    }
}

Also, the ThreadPool is a shared resource and performing any blocking action on a Threadpool thread can exhaust it. Even if your code did work, it would need to be refactored to address this resource starvation issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM