6

My program is a server which handles incoming requests. Each valid request is wrapped in NSOperation and passed to a normal NSOperationQueue.

Each NSOpearation processes its request. In some cases, there is contention at a NSDictionary which I use dispatch_queue (concurrent queue), dispatch_barrier_async(when set value) and dispatch_sync(when get value) to make this NSDictionary thread-safe.

I test my program with 100 requests concurrently then the process freezes sometimes. I kill the process with SIGSEGV to see crash log.

Most of the threads stuck at dispatch_sync of this queue. And there is a note below

Dispatch Thread Soft Limit Reached: 64 (too many dispatch threads blocked in synchronous operations)

What does this note really mean? What is its behavior? I cannot find information about this limit. How can I fix this issue?

I can think of 2 possible ways to avoid this problem. (which I'm going to test them and will update later)

  1. Use dispatch_semaphore to limit submitting the block to this concurrent queue.
  2. Limit maxConcurrentOperationCount of the NSOperationQueue

Do you have a better solution?

bdash
  • 18,110
  • 1
  • 59
  • 91
teerapap
  • 5,303
  • 7
  • 33
  • 40
  • This question should help explain somewhat: http://stackoverflow.com/questions/7213845/number-of-threads-created-by-gcd – Quinn Taylor Mar 02 '13 at 06:48
  • 1
    Your solutions are basically the correct ones. If you must do blocking work in concurrent queues, you need to limit the amount of parallelism you allow. libdispatch will only self-limit for cpu-bound work. – Catfish_Man Sep 25 '14 at 20:27
  • i get the same error with "setMaxConcurrentOperationCount :NSOperationQueueDefaultMaxConcurrentOperationCount". – Stephane Dec 16 '14 at 11:04
  • @Stephane Yep, you want to set it to some fixed number that keeps you below the max worker thread count. – Rob Jan 07 '19 at 21:44

1 Answers1

0

I can think of 2 possible ways to avoid this problem. (which I'm going to test them and will update later)

  1. Use dispatch_semaphore to limit submitting the block to this concurrent queue.
  2. Limit maxConcurrentOperationCount of the NSOperationQueue.

Yes, those are two common patterns. For the sake of future readers, the other solution to this “exhausting worker threads” problem is Objective-C's dispatch_apply, also known as concurrentPerform in Swift, which allows concurrent operations in a manner that won’t exhaust your pool of worker threads. But that’s really only applicable when launching a whole series of tasks up front (e.g. you want to parallelize a for loop), not the scenario you outline in your question. But, still, for the record, dispatch_apply/concurrentPerform is the third common solution for this general problem.

I cannot find information about this limit.

This used to be covered really nicely in WWDC 2012 video Asynchronous Design Patterns with Blocks, GCD, and XPC, but that video is no longer available (other WWDC 2012 videos are, but not that one, curiously). But they do walk through the limited worker thread issue in WWDC 2015 video Building Responsive and Efficient Apps with GCD.

Rob
  • 415,655
  • 72
  • 787
  • 1,044