Nested Invocations
3 min read
3 min read
3 min read
3 min read
A nested invocation is an invocation made from a dispatch or from the callback of an asynchronous invocation.
Deadlocks with Nested Invocations
Nested invocations are common, but they can deadlock. To avoid deadlocks, do not hold a shared resource, such as a mutex or a thread of an Ice thread pool, while waiting. The rest of this page shows the common case, a nested invocation made from a dispatch; the same rule applies to a callback.
A synchronous dispatch holds the thread that executes it, by default a thread of the server thread pool, until it returns, and a synchronous twoway invocation blocks its thread until the response arrives. A synchronous invocation made from a synchronous dispatch therefore holds a dispatch thread while it waits. If the invocation depends, directly or indirectly, on another dispatch from the same thread pool, the two can deadlock:
Nested invocation deadlock.
In this example, all the calls are synchronous, and both servers use the default server thread pool, which has a single thread. Server A's thread is blocked waiting for opB to complete, but Server B cannot complete opB until Server A dispatches its callback. Neither invocation can complete.
A larger server thread pool avoids this deadlock only while fewer nested invocations are pending than the pool has threads. To avoid exhausting the dispatch threads, release the dispatch thread while the nested invocation is pending: implement the outer operation with asynchronous dispatch (AMD), make the nested invocation asynchronously, and complete the dispatch when the nested invocation completes. Making the nested invocation asynchronously and then waiting for its result in the dispatch thread still holds that thread. With asynchronous dispatch, you can also make the synchronous invocation from a thread of your own instead of an Ice thread pool thread.
In Swift, a dispatch runs in its own task and a nested invocation is awaited, so waiting holds no thread of an Ice thread pool.