The ACE Task Framework
Sidebar 17: The C++ Trait Idiom
5.3 The ACE Task Class
ACE_Service_Config::open (argc, argv);
ACE_Reactor::instance ()->run_reactor_event_loop ();
return 0;
}
5.3 The ACE Task Class
Motivation
Although theACE_Thread_Managerclass provides a portable threading ab-straction, the threads it spawns and manages are not object-oriented, i.e., they are C-style functions rather than objects. C-style functions make it hard to associate data members and methods with a thread. To resolve these issues, ACE provides theACE_Taskclass.
Class Capabilities
TheACE_Taskclass is the basis of ACE’s object-oriented concurrency frame-work. It provides the following capabilities:
It uses an instance ofACE_Message_Queuefrom Section 5.2 to queue messages that are passed between tasks.
It can be used in conjunction with the ACE_Thread_Managerto be-come an active object [SSRB00] and process its queued messages in one or more threads of control.
Since it inherits from ACE_Service_Object, instances of ACE_Task can be linked/unlinked dynamically via the ACE Service Configurator framework from Chapter 4, which implements the Component Con-figurator pattern [SSRB00].
Since ACE_Service_Object inherits from ACE_Event_Handler, in-stances of ACE_Task can serve as concrete event handlers via the ACE Reactor framework from Chapter 3, which implements the Reac-tor pattern [SSRB00].
140 Section 5.3 The ACE Task Class
It can be subclassed to create application-defined methods that queue and/or process messages.
Our focus in this section is on theACE_Taskcapabilities for message pro-cessing. It obtains the event handling and dynamic linking/unlinking ca-pabilities by inheriting from the ACE_Service_Object class described in the previous two chapters.
The interface for theACE_Taskclass is shown in Figure 5.5 and its key methods are shown in the following table:
Method Description
open() close()
Hook methods that perform application-defined initialization and termination activities.
put() A hook method that can be used to pass a message to a task, where it can be processed immediately or queued for subsequent processing in thesvc()hook method.
svc() A hook method run by one or more threads to process messages that are placed on the queue viaput().
getq() putq()
Insert and remove messages from the task’s message queue (only visible to subclasses ofACE_Task).
thr_mgr() Get and set a pointer to the task’sACE_Thread_Manager.
activate() Uses the ACE_Thread_Managerto convert the task into an active object that runs thesvc()method in one or more threads.
ACE_Task must be customized by subclasses to provide application-defined functionality by overriding its hook methods. For example, ACE_
Task subclasses can override its open() and close() hook methods to perform application-definedACE_Taskinitialization and termination activ-ities. These activities include spawning and canceling threads and allocat-ing and freeallocat-ing resources, such as connection control blocks, I/O handles, and synchronization locks. ACE_Tasksubclasses can perform application-defined processing on messages by overriding its put() and svc() hook methods to implement the following two message processing models:
1. Synchronous processing. The put() method is the entry point into an ACE_Task, i.e., it’s used to pass messages to a task. To minimize over-head, pointers toACE_Message_Blockobjects are passed between tasks to avoid copying their data. Task processing can be performed synchronously in the context of theput()method if it executes solely as a passive object, i.e., if its caller’s thread is borrowed for the duration of its processing.
Section 5.3 The ACE Task Class 141
+ open (args : void *) : int + close (flags : u_long) : int + put (mb : ACE_Message_Block *,
timeout : ACE_Time_Value *) : int + svc () : int
+ getq (mb : ACE_Message_Block *&,
timeout : ACE_Time_Value *) : int + putq (mb : ACE_Message_Block *,
timeout : ACE_Time_Value *) : int + activate (flags : long, threads : int) : int + thr_mgr (): ACE_Thread_Manager *
+ thr_mgr (mgr : ACE_Thread_Manager *) + thr_mgr_ : ACE_Thread_Manager * + thr_count_ : size_t
+ msg_queue_ : ACE_Message_Queue * ACE_Task
Figure 5.5: TheACE TaskClass
2. Asynchronous processing. The svc() method can be overridden by a subclass and used to perform application-defined processing asyn-chronously with respect to other activities in an application. Unlikeput(), the svc() method is not invoked by a client of a task directly. Instead, it’s invoked by one or more threads when a task becomes an active ob-ject, i.e., after its activate() method is called. This method uses the ACE_Thread_Managerassociated with anACE_Taskto spawn one or more threads, as follows:
template <class SYNCH_STRATEGY> int
ACE_Task<SYNCH_STRATEGY>::activate (long flags, int n_threads,
/* Other params omitted */) {
// ...
thr_mgr ()->spawn_n (n_threads,
&ACE_Task<SYNCH_STRATEGY>::svc_run, ACE_static_cast (void *, this), flags,
/* Other params omitted */);
// ...
142 Section 5.3 The ACE Task Class
1
1.. AACCEE__TTaasskk::::aaccttiivvaattee (()) 22.. AACCEE__TThhrreeaadd__MMaannaaggeerr::::ssppaawwnn
44.. tteemmppllaattee <<SSYYNNCCHH__SSTTRRAATTEEGGYY>> vvooiidd **
AACCEE__TTaasskk<<SSYYNNCCHH__SSTTRRAATTEEGGYY>>::::ssvvcc__rruunn ((AACCEE__TTaasskk<<SSYYNNCCHH__SSTTRRAATTEEGGYY>> **tt)) {{
//// ...
vvooiidd **ssttaattuuss == tt-->>ssvvcc (());;
//// ...
rreettuurrnn ssttaattuuss;; //// RReettuurrnn vvaalluuee ooff tthhrreeaadd..
}}
Figure 5.6: Task Activate Behavior
}
TheACE_Task::svc_run()method is a static method used as an adapter function. It runs in the newly spawned thread(s) of control, which pro-vide an execution context for the svc() hook method. Figure 5.6 illus-trates the steps associated with activating an ACE_Task using the Win32 CreateThread()function to spawn the thread. Naturally, the ACE_Task class shields applications from any Win32-specific details.
When an ACE_Task subclass executes as an active object, its svc() method often runs an event loop that waits for messages to arrive on the task’sACE_Message_Queue. This queue can be used to buffer a sequence of data messages and control messages for subsequent processing by a task’s svc() method. As messages arrive and are enqueued by a task’s put() method, the svc() method runs in separate thread(s) dequeueing the messages and performing application-defined processing concurrently, as shown in Figure 5.7. Sidebar 18 compares and contrasts theACE_Task
2 55:: ddoo__wwoorrkk((mmssgg)) 66:: ppuutt ((mmssgg))
:
: AACCEE__MMeessssaaggee__QQuueeuuee
tt11 :: SSuubbTTaasskk
:: TTaasskk SSttaattee
:
: AACCEE__MMeessssaaggee__QQuueeuuee
tt22 :: SSuubbTTaasskk
:: TTaasskk SSttaattee
:
: AACCEE__MMeessssaaggee__QQuueeuuee
tt33 :: SSuubbTTaasskk
:: TTaasskk SSttaattee
Figure 5.7: Passing Messages Between ACE TaskObjects capabilities with the JavaRunnableinterface and Threadclass.
Section 5.3 The ACE Task Class 143