Communicator Shutdown and Destruction
On this page:
Communicator Operations
Once you have successfully created a communicator, it is essential that you destroy
this communicator before exiting your application. Destroying a communicator ensures an orderly closure of connections opened by this communicator, the clean termination of all the threads started by this communicator and more.
A communicator provides four operations related to shutdown and destruction:
["clr:implements:_System.IDisposable", "java:implements:java.lang.AutoCloseable"] local interface Communicator { ["cpp:noexcept"] void shutdown(); ["cpp:noexcept"] void waitForShutdown(); ["cpp:noexcept"] bool isShutdown(); ["cpp:noexcept"] void destroy(); // ... }
shutdown
This operation shuts down the server side of the Ice run time:- Operation invocations that are in progress at the time
shutdown
is called are allowed to complete normally.shutdown
does not wait for these operations to complete; whenshutdown
returns, you know that no new incoming requests will be dispatched, but operations that were already in progress at the time you calledshutdown
may still be running. You can wait for still-executing operations to complete by callingwaitForShutdown
. - Operation invocations that arrive after the server has called
shutdown
either fail with aConnectFailedException
or are transparently redirected to a new instance of the server (via IceGrid). - Note that
shutdown
initiates deactivation of all object adapters associated with the communicator, so attempts to use an adapter onceshutdown
has completed raise anObjectAdapterDeactivatedException
.
- Operation invocations that are in progress at the time
waitForShutdown
On the server side, this operation suspends the calling thread until the communicator has shut down (that is, until no more operations are executing in the server). This allows you to wait until the server is idle before you destroy the communicator.
On the client side,waitForShutdown
simply waits until another thread has calledshutdown
ordestroy
.
isShutdown
This operation returns true ifshutdown
has been invoked on the communicator. A return value of true does not necessarily indicate that the shutdown process has completed, only that it has been initiated. An application that needs to know whether shutdown is complete can callwaitForShutdown
. If the blocking nature ofwaitForShutdown
is undesirable, the application can invoke it from a separate thread.
destroy
This operation destroys the communicator and all its associated resources, such as threads, communication endpoints, object adapters, and memory resources. Once you have destroyed the communicator (and therefore destroyed the run time for that communicator), you must not call any other Ice operation (other than to create another communicator).destroy
does not throw any exception, and callingdestroy
multiple times on the same communicator is perfectly safe and correct.
If you calldestroy
without callingshutdown
, the call waits for all executing operation invocations to complete before it returns (that is, the implementation ofdestroy
implicitly callsshutdown
followed bywaitForShutdown
).shutdown
(and, therefore,destroy
) deactivates all object adapters that are associated with the communicator. Sincedestroy
blocks until all operation invocations complete, a servant will deadlock if it invokesdestroy
on its own communicator while executing a dispatched operation.On the client side, calling
destroy
while operations are still executing causes those operations to terminate with aCommunicatorDestroyedException
.
Most language mappings provide constructs to destroy
the communicator automatically when leaving a scope:
- C++: the
Ice::CommunicatorHolder
RAII helper class - C#:
Communicator
implements theIDisposable
interface, which allows you to initialize a communicator in ausing
statement - Java:
Communicator
implementsjava.lang.AutoCloseable
, which allows you to initialize a communicator in a try-with-resources statement - Python:
Communicator
implements the Python context manager protocol, which allows you to callinitialize
in awith
statement - Ruby:
Ice::initialize
accepts an optional block, which destroys the communicator automatically at the end of the block
Common Patterns
Pure Client
In a pure client - a client that does not create any object adapter - there is no need to shutdown your communicator so you typically destroy
your communicator without an intermediate explicit shutdown
.
Server
In a server, you can destroy your communicator or first shut it down and only later destroy it.
- Plain Destroy
In a server, a communicatordestroy
with no prior shutdown is correct provided thisdestroy
is not called from an operation dispatch, and you don't need the communicator afterwards. For example, many C# and Java servers in ice-demos destroy their communicators in response to a CTRL-C or similar signal. This is the simplest signal handling strategy since C# (by default) and Java (always) terminate the application once the signal handlers have finished execution.
- Shutdown with WaitForShutdown and Destroy
You can initiate the shutdown of your communicator in one thread (withshutdown
) while another thread is blocked onwaitForShutdown
. When the thread blocked onwaitForShutdown
is freed, it has a shutdown but not destroyed communicator, still usable for remote invocations. This thread is then typically responsible todestroy
the communicator.
For example, all the ice-demos applications use this pattern to implement remote shutdown: the shutdown operation implementation callsshutdown
on the communicator, while the main thread waits onwaitForShutdown
and later destroys the communicator. C++, Python and some C# demo servers also shutdown their communicator in response to a CTRL-C signal or similar signal. With C++, Python and optionally in C#, the application keeps running after a signal is handled, so we can have the main thread perform post-shutdown cleanups (if needed) and then destroy the communicator before completing cleanly.