TibrvEventOnComplete::onComplete()

Method

Declaration

virtual void onComplete(
    TibrvEvent* destroyedEvent) = 0;

Purpose

A program can destroy an event object even when its callback method is running in one or more threads. Multi-threaded programs can define methods of this type to discover when all callback methods in progress have completed.

Parameter

Description

destroyedEvent

This parameter receives the event object. This object is identical to the object that the program created to express event interest.

However, by the time this method runs, the event is already destroyed; this method cannot use the event object in Rendezvous calls.

Remarks

This type of method is important in two situations:

An event callback method calls TibrvEvent::destroy() to destroy its event, and the program must do additional processing after the rest of the callback method has completed.
Several threads dispatch an event (so the event callback method can be running in several threads) and the program must do additional processing after the callback method has completed in all threads.

Upon return from TibrvEvent::destroy(), the destroyed event’s callback method can no longer begin to run. However, in each thread where the callback method is already in progress, that callback method does continue to run until complete.

The completion callback can still extract closure data from the event, even though the event is already destroyed.

TibrvEvent::destroy() accepts an argument of type TibrvEventOnComplete. Rendezvous software ensures that the completion method runs when the last callback-in-progress has completed.

Timing and Context

This completion method can run in two situations:

Completion when Callback Methods are in Progress illustrates a situation in which the program calls TibrvEvent::destroy() while callback methods of the destroyed event are in progress. When the last of those callback methods completes, Rendezvous software runs the completion method immediately, in the same thread as the callback method that completes last.
Completion when Callback Methods are Not in Progress illustrates a situation in which the program calls TibrvEvent::destroy() when the destroyed event’s callback method is not running in any thread. In this case, TibrvEvent::destroy() calls the completion method before returning.

Notice that in this situation, the completion method runs in the program context, instead of the usual context of a callback method. In rare instances, deadlock can occur, resulting from unintended interactions between mutex operations in the program context before the destroy call, and mutex operations in the program’s completion method code.

To protect against this type of deadlock, programmers can use a straightforward thought-experiment as a preventive test. Expand the completion method code immediately after the call to TibrvEvent::destroy()—as it would run when the destroyed event’s callback method is not running in any thread. Trace mutex locking activity within this context to determine whether the resulting code could violate established rules for proper use of mutex locks.

      ...
      mutex lock operations
      ...
      myEvent::destoy()
      expand completion method code here, and check for violations of mutex rules
      ...

Potential violations and conflicts usually become apparent during this exercise. Remember, it is the programmer’s responsibility to prevent deadlock.

Figure 215: Completion when Callback Methods are in Progress

Figure 216: Completion when Callback Methods are Not in Progress

See Also

TibrvIOEvent::create()

TibrvListener::create()

TibrvTimer::create()

TibrvEvent::destroy()