/* -*- C++ -*- */ // $Id$ // ============================================================================ // // = LIBRARY // ace // // = FILENAME // Thread_Manager.h // // = AUTHOR // Doug Schmidt // // ============================================================================ #ifndef ACE_THREAD_MANAGER_H #define ACE_THREAD_MANAGER_H #include "ace/pre.h" #include "ace/Thread.h" #include "ace/Thread_Adapter.h" #if !defined (ACE_LACKS_PRAGMA_ONCE) # pragma once #endif /* ACE_LACKS_PRAGMA_ONCE */ #include "ace/Synch.h" #include "ace/Containers.h" #include "ace/Free_List.h" #include "ace/Singleton.h" #include "ace/Log_Msg.h" // The following macros control how a Thread Manager manages a pool of // Thread_Descriptor. Currently, the default behavior is not to // preallocate any thread descriptor and never (well, almost never) // free up any thread descriptor until the Thread Manager gets // destructed. Which means, once your system is stable, you rarely // need to pay the price of memory allocation. On a deterministic // system, which means, the number of threads spawned can be // determined before hand, you can either redefine the memory pool // size macros to suit your need or constructed the Thread_Manager // accordingly. That way, you don't pay the price of memory // allocation when the system is really doing its job. OTOH, on // system with resources constraint, you may want to lower the size of // ACE_DEFAULT_THREAD_MANAGER_HWM to avoid unused memory hanging // around. #if !defined (ACE_DEFAULT_THREAD_MANAGER_PREALLOC) # define ACE_DEFAULT_THREAD_MANAGER_PREALLOC 0 #endif /* ACE_DEFAULT_THREAD_MANAGER_PREALLOC */ #if !defined (ACE_DEFAULT_THREAD_MANAGER_LWM) # define ACE_DEFAULT_THREAD_MANAGER_LWM 1 #endif /* ACE_DEFAULT_THREAD_MANAGER_LWM */ #if !defined (ACE_DEFAULT_THREAD_MANAGER_INC) # define ACE_DEFAULT_THREAD_MANAGER_INC 1 #endif /* ACE_DEFAULT_THREAD_MANAGER_INC */ #if !defined (ACE_DEFAULT_THREAD_MANAGER_HWM) # define ACE_DEFAULT_THREAD_MANAGER_HWM ACE_DEFAULT_FREE_LIST_HWM // this is a big number #endif /* ACE_DEFAULT_THREAD_MANAGER_HWM */ // This is the synchronization mechanism used to prevent a thread // descriptor gets removed from the Thread_Manager before it gets // stash into it. If you want to disable this feature (and risk of // corrupting the freelist,) you define the lock as ACE_Null_Mutex. // Usually, if you can be sure that your threads will run for an // extended period of time, you can safely disable the lock. #if !defined (ACE_DEFAULT_THREAD_MANAGER_LOCK) # define ACE_DEFAULT_THREAD_MANAGER_LOCK ACE_SYNCH_MUTEX #endif /* ACE_DEFAULT_THREAD_MANAGER_LOCK */ // Forward declarations. class ACE_Task_Base; class ACE_Thread_Manager; class ACE_Thread_Descriptor; #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) class ACE_Export ACE_At_Thread_Exit { // = TITLE // Contains a method to be applied when a thread is terminated. friend class ACE_Thread_Descriptor; friend class ACE_Thread_Manager; public: // Default constructor ACE_At_Thread_Exit (void); // The destructor virtual ~ACE_At_Thread_Exit (void); // has the ownership? int is_owner (void) const; // Set the ownership of the . int is_owner (int owner); // This was applied? int was_applied (void) const; // Set applied state of . int was_applied (int applied); protected: ACE_At_Thread_Exit *next_; // The next hook in the list. // Do the apply if necessary void do_apply (void); virtual void apply (void) = 0; // The apply method. ACE_Thread_Descriptor* td_; // The Thread_Descriptor where this at is registered. int was_applied_; // The at was applied? int is_owner_; // The at has the ownership of this? }; class ACE_Export ACE_At_Thread_Exit_Func : public ACE_At_Thread_Exit { public: // Constructor ACE_At_Thread_Exit_Func (void *object, ACE_CLEANUP_FUNC func, void *param = 0); virtual ~ACE_At_Thread_Exit_Func (void); protected: void *object_; // The object to be cleanup ACE_CLEANUP_FUNC func_; // The cleanup func void *param_; // A param if required // The apply method void apply (void); }; #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ class ACE_Export ACE_Thread_Descriptor_Base : public ACE_OS_Thread_Descriptor { // = TITLE // Basic information for thread descriptors. These information // gets extracted out because we need it after a thread is // terminated. friend class ACE_Thread_Manager; friend class ACE_Double_Linked_List; friend class ACE_Double_Linked_List_Iterator_Base; friend class ACE_Double_Linked_List_Iterator; friend class ACE_Double_Linked_List; friend class ACE_Double_Linked_List_Iterator_Base; friend class ACE_Double_Linked_List_Iterator; public: ACE_Thread_Descriptor_Base (void); ~ACE_Thread_Descriptor_Base (void); // = We need the following operators to make Borland happy. int operator== (const ACE_Thread_Descriptor_Base &rhs) const; // Equality operator. int operator!= (const ACE_Thread_Descriptor_Base &rhs) const; // Inequality operator. int grp_id (void); // Group ID. ACE_UINT32 state (void); // Current state of the thread. ACE_Task_Base *task (void); // Return the pointer to an or NULL if there's no // associated with this thread.; protected: void reset (void); // Reset this base thread descriptor. ACE_thread_t thr_id_; // Unique thread ID. ACE_hthread_t thr_handle_; // Unique handle to thread (used by Win32 and AIX). int grp_id_; // Group ID. ACE_UINT32 thr_state_; // Current state of the thread. ACE_Task_Base *task_; // Pointer to an or NULL if there's no // . ACE_Thread_Descriptor_Base *next_; ACE_Thread_Descriptor_Base *prev_; // We need these pointers to maintain the double-linked list in a // thread managers. }; class ACE_Export ACE_Thread_Descriptor : public ACE_Thread_Descriptor_Base { // = TITLE // Information for controlling threads that run under the control // of the . #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) friend class ACE_At_Thread_Exit; #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ friend class ACE_Thread_Manager; friend class ACE_Double_Linked_List; friend class ACE_Double_Linked_List_Iterator; public: // = Initialization method. ACE_Thread_Descriptor (void); // = Accessor methods. ACE_thread_t self (void); // Unique thread id. void self (ACE_hthread_t &); // Unique handle to thread (used by Win32 and AIX). void dump (void) const; // Dump the state of an object. #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) void log_msg_cleanup(ACE_Log_Msg* log_msg); // This cleanup function must be called only for ACE_TSS_cleanup. // The ACE_TSS_cleanup delegate Log_Msg instance destruction when // Log_Msg cleanup is called before terminate. int at_exit (ACE_At_Thread_Exit* cleanup); // Register an At_Thread_Exit hook and the ownership is acquire by // Thread_Descriptor, this is the usual case when the AT is dynamically // allocated. int at_exit (ACE_At_Thread_Exit& cleanup); // Register an At_Thread_Exit hook and the ownership is retained for the // caller. Normally used when the at_exit hook is created in stack. #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ int at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param); // Register an object (or array) for cleanup at thread termination. // "cleanup_hook" points to a (global, or static member) function // that is called for the object or array when it to be destroyed. // It may perform any necessary cleanup specific for that object or // its class. "param" is passed as the second parameter to the // "cleanup_hook" function; the first parameter is the object (or // array) to be destroyed. Returns 0 on success, non-zero on // failure: -1 if virtual memory is exhausted or 1 if the object (or // arrayt) had already been registered. ~ACE_Thread_Descriptor (void); // Do nothing destructor to keep some compilers happy void acquire_release (void); // Do nothing but to acquire the thread descriptor's lock and // release. This will first check if the thread is registered or // not. If it is already registered, there's no need to reacquire // the lock again. This is used mainly to get newly spawned thread // in synch with thread manager and prevent it from accessing its // thread descriptor before it gets fully built. This function is // only called from ACE_Log_Msg::thr_desc. ACE_INLINE_FOR_GNUC void set_next (ACE_Thread_Descriptor *td); ACE_INLINE_FOR_GNUC ACE_Thread_Descriptor *get_next (void); // Set/get the pointer. These are required by the // ACE_Free_List. ACE_INLINE is specified here because one version // of g++ couldn't grok this code without it. private: void reset (ACE_Thread_Manager *tm); // Reset this thread descriptor. #if !defined (ACE_USE_ONE_SHOT_AT_THREAD_EXIT) void at_pop (int apply = 1); // Pop an At_Thread_Exit from at thread termination list, apply the at // if apply is true. void at_push (ACE_At_Thread_Exit* cleanup, int is_owner = 0); // Push an At_Thread_Exit to at thread termination list and set the // ownership of at. void do_at_exit (void); // Run the AT_Thread_Exit hooks. void terminate (void); // terminate realize the cleanup process to thread termination ACE_Log_Msg *log_msg_; // Thread_Descriptor is the ownership of ACE_Log_Msg if log_msg_!=0 // This can occur because ACE_TSS_cleanup was executed before terminate. ACE_At_Thread_Exit *at_exit_list_; // The AT_Thread_Exit list #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ ACE_Cleanup_Info cleanup_info_; // Stores the cleanup info for a thread. // @@ Note, this should be generalized to be a stack of // s. #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) ACE_Thread_Manager* tm_; // Pointer to an or NULL if there's no // . #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ ACE_DEFAULT_THREAD_MANAGER_LOCK *sync_; // Registration lock to prevent premature removal of thread descriptor. #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) int terminated_; // Keep track of termination status. #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ }; // Forward declaration. class ACE_Thread_Control; // This typedef should be (and used to be) inside the // ACE_Thread_Manager declaration. But, it caused compilation // problems on g++/VxWorks/i960 with -g. Note that // ACE_Thread_Manager::THR_FUNC is only used internally in // ACE_Thread_Manager, so it's not useful for anyone else. // It also caused problems on IRIX5 with g++. #if defined (__GNUG__) typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int); #endif /* __GNUG__ */ class ACE_Export ACE_Thread_Manager { // = TITLE // Manages a pool of threads. // // = DESCRIPTION // This class allows operations on groups of threads atomically. // The default behavior of thread manager is to wait on // all threads under it's management when it gets destructed. // Therefore, remember to remove a thread from thread manager if // you don't want it to wait for the thread. There are also // function to disable this default wait-on-exit behavior. // However, if your program depends on turning this off to run // correctly, you are probably doing something wrong. Rule of // thumb, use ACE_Thread to manage your daemon threads. // // Notice that if there're threads live beyond the scope of //
, you are sure to have resource leaks in your program. // Remember to wait on threads before exiting
if that // could happen in your programs. public: friend class ACE_Thread_Control; #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) friend class ACE_Thread_Descriptor; #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ #if !defined (__GNUG__) typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int); #endif /* !__GNUG__ */ // These are the various states a thread managed by the // can be in. enum { ACE_THR_IDLE = 0x00000000, // Uninitialized. ACE_THR_SPAWNED = 0x00000001, // Created but not yet running. ACE_THR_RUNNING = 0x00000002, // Thread is active (naturally, we don't know if it's actually // *running* because we aren't the scheduler...). ACE_THR_SUSPENDED = 0x00000004, // Thread is suspended. ACE_THR_CANCELLED = 0x00000008, // Thread has been cancelled (which is an indiction that it needs to // terminate...). ACE_THR_TERMINATED = 0x00000010, // Thread has shutdown, but the slot in the thread manager hasn't // been reclaimed yet. ACE_THR_JOINING = 0x10000000 // Join operation has been invoked on the thread by thread manager. }; // = Initialization and termination methods. ACE_Thread_Manager (size_t preaolloc = 0, size_t lwm = ACE_DEFAULT_THREAD_MANAGER_LWM, size_t inc = ACE_DEFAULT_THREAD_MANAGER_INC, size_t hwm = ACE_DEFAULT_THREAD_MANAGER_HWM); virtual ~ACE_Thread_Manager (void); #if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) static ACE_Thread_Manager *instance (void); // Get pointer to a process-wide . static ACE_Thread_Manager *instance (ACE_Thread_Manager *); // Set pointer to a process-wide and return // existing pointer. static void close_singleton (void); // Delete the dynamically allocated Singleton #endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ int open (size_t size = 0); // No-op. Currently unused. int close (void); // Release all resources. // By default, this method will wait till all threads // exit. However, when called from , most global resources // are destroyed and thus, we don't try to wait but just clean up the thread // descriptor list. // The * argument to each of the family member // functions is interpreted and used as shown in the following // table. NOTE: the final option, to provide task names, is _only_ // supported on VxWorks! // // Value of ACE_thread_t * argument Use Platforms // ================================ ========================== ========= // 0 Not used. All // non-0 (and points to 0 char * The task name is passed All // on VxWorks) back in the char *. // non-0, points to non-0 char * The char * is used as VxWorks only // the task name. The // argument is not modified. int spawn (ACE_THR_FUNC func, void *args = 0, long flags = THR_NEW_LWP | THR_JOINABLE, ACE_thread_t * = 0, ACE_hthread_t *t_handle = 0, long priority = ACE_DEFAULT_THREAD_PRIORITY, int grp_id = -1, void *stack = 0, size_t stack_size = 0); // Create a new thread, which executes . // Returns: on success a unique group id that can be used to control // other threads added to the same group. On failure, returns -1. int spawn_n (size_t n, ACE_THR_FUNC func, void *args = 0, long flags = THR_NEW_LWP | THR_JOINABLE, long priority = ACE_DEFAULT_THREAD_PRIORITY, int grp_id = -1, ACE_Task_Base *task = 0, ACE_hthread_t thread_handles[] = 0, void *stack[] = 0, size_t stack_size[] = 0); // Create N new threads, all of which execute . // Returns: on success a unique group id that can be used to control // all of the threads in the same group. On failure, returns -1. int spawn_n (ACE_thread_t thread_ids[], size_t n, ACE_THR_FUNC func, void *args, long flags, long priority = ACE_DEFAULT_THREAD_PRIORITY, int grp_id = -1, void *stack[] = 0, size_t stack_size[] = 0, ACE_hthread_t thread_handles[] = 0, ACE_Task_Base *task = 0); // Spawn N new threads, which execute with argument . // If != 0 the thread_ids of successfully spawned // threads will be placed into the buffer (which must // be the same size as ). If != 0 it is assumed to be an // array of pointers to the base of the stacks to use for the // threads being spawned. If != 0 it is assumed to be // an array of values indicating how big each of the // corresponding s are. If != 0 it is // assumed to be an array of thread_handles that will be // assigned the values of the thread handles being spawned. Returns // -1 on failure ( will explain...), otherwise returns the // group id of the threads. void *exit (void *status = 0, int do_thread_exit = 1); // Called to clean up when a thread exits. If is // non-0 then is called to exit the thread, in // which case is passed as the exit value of the thread. // Should _not_ be called by main thread. int wait (const ACE_Time_Value *timeout = 0, int abandon_detached_threads = 0); // Block until there are no more threads running in the // or expires. Note that is // treated as "absolute" time. Returns 0 on success and -1 on // failure. If is set, wait will first // check thru its thread list for threads with THR_DETACHED or // THR_DAEMON flags set and remove these threads. Notice that // unlike other wait_* function, by default, does wait on // all thread spawned by this thread_manager no matter the detached // flags are set or not unless it is called with // flag set. // NOTE that if this function is called while the ACE_Object_Manager // is shutting down (as a result of program rundown via ACE::fini), // it will not wait for any threads to complete. If you must wait for // threads spawned by this thread manager to complete and you are in a // ACE rundown situation (such as your object is being destroyed by the // ACE_Object_Manager) you can use wait_grp instead. int join (ACE_thread_t tid, void **status = 0); // Join a thread specified by . Do not wait on a detached thread. int wait_grp (int grp_id); // Block until there are no more threads running in a group. // Returns 0 on success and -1 on failure. Notice that wait_grp // will not wait on detached threads. // = Accessors for ACE_Thread_Descriptors. ACE_Thread_Descriptor *thread_desc_self (void); // Get a pointer to the calling thread's own thread_descriptor. // This must be called from a spawn thread. This function will // fetch the info from TSS. ACE_Thread_Descriptor *thread_descriptor (ACE_thread_t); // Return a pointer to the thread's Thread_Descriptor, // 0 if fail. ACE_Thread_Descriptor *hthread_descriptor (ACE_hthread_t); // Return a pointer to the thread's Thread_Descriptor, // 0 if fail. int thr_self (ACE_hthread_t &); // Return the "real" handle to the calling thread, caching it if // necessary in TSS to speed up subsequent lookups. This is // necessary since on some platforms (e.g., Win32) we can't get this // handle via direct method calls. Notice that you should *not* // close the handle passed back from this method. It is used // internally by Thread Manager. On the other hand, you *have to* // use this internal thread handle when working on Thread_Manager. // Return -1 if fail. ACE_thread_t thr_self (void); // Return the unique ID of the thread. This is not strictly // necessary (because a thread can always just call // ). However, we put it here to be complete. ACE_Task_Base *task (void); // Returns a pointer to the current we're executing // in if this thread is indeed running in an , else // return 0. // = Suspend methods, which isn't supported on POSIX pthreads (will not block). int suspend_all (void); // Suspend all threads int suspend (ACE_thread_t); // Suspend a single thread. int suspend_grp (int grp_id); // Suspend a group of threads. int testsuspend (ACE_thread_t t_id); // True if is inactive (i.e., suspended), else false. // = Resume methods, which isn't supported on POSIX pthreads (will not block). int resume_all (void); // Resume all stopped threads int resume (ACE_thread_t); // Resume a single thread. int resume_grp (int grp_id); // Resume a group of threads. int testresume (ACE_thread_t t_id); // True if is active (i.e., resumed), else false. // = Send signals to one or more threads without blocking. int kill_all (int signum); // Send to all stopped threads. Not supported on platforms // that do not have advanced signal support, such as Win32. int kill (ACE_thread_t, int signum); // Send the to a single thread. Not supported on platforms // that do not have advanced signal support, such as Win32. int kill_grp (int grp_id, int signum); // Send to a group of threads, not supported on platforms // that do not have advanced signal support, such as Win32. // = Cancel methods, which provides a cooperative thread-termination mechanism (will not block). int cancel_all (int async_cancel = 0); // Cancel's all the threads. int cancel (ACE_thread_t, int async_cancel = 0); // Cancel a single thread. int cancel_grp (int grp_id, int async_cancel = 0); // Cancel a group of threads. int testcancel (ACE_thread_t t_id); // True if is cancelled, else false. // = Set/get group ids for a particular thread id. int set_grp (ACE_thread_t, int grp_id); int get_grp (ACE_thread_t, int &grp_id); // = The following methods are new methods which resemble current // methods in . For example, the // method resembles the method, and // resembles . // = Operations on ACE_Tasks. int wait_task (ACE_Task_Base *task); // Block until there are no more threads running in . Returns // 0 on success and -1 on failure. Note that will not // wait on detached threads. int suspend_task (ACE_Task_Base *task); // Suspend all threads in an ACE_Task. int resume_task (ACE_Task_Base *task); // Resume all threads in an ACE_Task. int kill_task (ACE_Task_Base *task, int signum); // Send a signal to all threads in an . int cancel_task (ACE_Task_Base *task, int async_cancel = 0); // Cancel all threads in an . If is non-0, // then asynchronously cancel these threads if the OS platform // supports cancellation. Otherwise, perform a "cooperative" // cancellation. // = Collect thread handles in the thread manager. Notice that // the collected information is just a snapshot. int hthread_within (ACE_hthread_t handle); int thread_within (ACE_thread_t tid); // Check if the thread is managed by the thread manager. Return true if // the thread is found, false otherwise. int num_tasks_in_group (int grp_id); // Returns the number of in a group. int num_threads_in_task (ACE_Task_Base *task); // Returns the number of threads in an . int task_list (int grp_id, ACE_Task_Base *task_list[], size_t n); // Returns in a list of up to in a // group. The caller must allocate the memory for . In // case of an error, -1 is returned. If no requested values are // found, 0 is returned, otherwise correct number of retrieved // values are returned. int thread_list (ACE_Task_Base *task, ACE_thread_t thread_list[], size_t n); // Returns in a list of up to thread ids in an // . The caller must allocate the memory for // . In case of an error, -1 is returned. If no // requested values are found, 0 is returned, otherwise correct // number of retrieved values are returned. int hthread_list (ACE_Task_Base *task, ACE_hthread_t hthread_list[], size_t n); // Returns in a list of up to thread handles in // an . The caller must allocate memory for // . In case of an error, -1 is returned. If no // requested values are found, 0 is returned, otherwise correct // number of retrieved values are returned. int thread_grp_list (int grp_id, ACE_thread_t thread_list[], size_t n); // Returns in a list of up to thread ids in a // group . The caller must allocate the memory for // . In case of an error, -1 is returned. If no // requested values are found, 0 is returned, otherwise correct // number of retrieved values are returned. int hthread_grp_list (int grp_id, ACE_hthread_t hthread_list[], size_t n); // Returns in a list of up to thread handles in // a group . The caller must allocate memory for // . int task_all_list (ACE_Task_Base *task_list[], size_t n); // Returns in a list of up to . The // caller must allocate the memory for . In case of an // error, -1 is returned. If no requested values are found, 0 is // returned, otherwise correct number of retrieved values are // returned. int thread_all_list (ACE_thread_t thread_list[], size_t n); // Returns in a list of up to thread ids. The // caller must allocate the memory for . In case of an // error, -1 is returned. If no requested values are found, 0 is // returned, otherwise correct number of retrieved values are // returned. // = Set/get group ids for a particular task. int set_grp (ACE_Task_Base *task, int grp_id); int get_grp (ACE_Task_Base *task, int &grp_id); int count_threads (void) const; // Return a count of the current number of threads active in the // . #if !defined(ACE_USE_ONE_SHOT_AT_THREAD_EXIT) int at_exit (ACE_At_Thread_Exit* cleanup); // Register an At_Thread_Exit hook and the ownership is acquire by // Thread_Descriptor, this is the usual case when the AT is dynamically // allocated. int at_exit (ACE_At_Thread_Exit& cleanup); // Register an At_Thread_Exit hook and the ownership is retained for the // caller. Normally used when the at_exit hook is created in stack. #endif /* !ACE_USE_ONE_SHOT_AT_THREAD_EXIT */ int at_exit (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param); // *** This function is deprecated. Please use the previous two // *** at_exit method. Notice that you should avoid mixing this method // *** with the previous two at_exit methods. // // Register an object (or array) for cleanup at // thread termination. "cleanup_hook" points to a (global, or // static member) function that is called for the object or array // when it to be destroyed. It may perform any necessary cleanup // specific for that object or its class. "param" is passed as the // second parameter to the "cleanup_hook" function; the first // parameter is the object (or array) to be destroyed. // "cleanup_hook", for example, may delete the object (or array). // If == 0, the will _NOT_ get cleanup at // thread exit. You can use this to cancel the previously added // at_exit. void wait_on_exit (int dowait); int wait_on_exit (void); // Access function to determine whether the Thread_Manager will // wait for its thread to exit or not when being closing down. void dump (void); // Dump the state of an object. ACE_ALLOC_HOOK_DECLARE; // Declare the dynamic allocation hooks. protected: virtual int spawn_i (ACE_THR_FUNC func, void *args, long flags, ACE_thread_t * = 0, ACE_hthread_t *t_handle = 0, long priority = ACE_DEFAULT_THREAD_PRIORITY, int grp_id = -1, void *stack = 0, size_t stack_size = 0, ACE_Task_Base *task = 0); // Create a new thread (must be called with locks held). void run_thread_exit_hooks (int i); // Run the registered hooks when the thread exits. ACE_Thread_Descriptor *find_thread (ACE_thread_t t_id); // Locate the index of the table slot occupied by . Returns // -1 if is not in the table doesn't contain . ACE_Thread_Descriptor *find_hthread (ACE_hthread_t h_id); // Locate the index of the table slot occupied by . Returns // -1 if is not in the table doesn't contain . ACE_Thread_Descriptor *find_task (ACE_Task_Base *task, int slot = -1); // Locate the thread descriptor address of the list occupied by // . Returns 0 if is not in the table doesn't contain // . int insert_thr (ACE_thread_t t_id, ACE_hthread_t, int grp_id = -1, long flags = 0); // Insert a thread in the table (checks for duplicates). int append_thr (ACE_thread_t t_id, ACE_hthread_t, ACE_UINT32, int grp_id, ACE_Task_Base *task = 0, long flags = 0, ACE_Thread_Descriptor *td = 0); // Append a thread in the table (adds at the end, growing the table // if necessary). void remove_thr (ACE_Thread_Descriptor *td, int close_handler); // Remove thread from the table. void remove_thr_all (void); // Remove all threads from the table. // = The following four methods implement a simple scheme for // operating on a collection of threads atomically. int check_state (ACE_UINT32 state, ACE_thread_t thread, int enable = 1); // Efficiently check whether is in a particular . // This call updates the TSS cache if possible to speed up // subsequent searches. int apply_task (ACE_Task_Base *task, ACE_THR_MEMBER_FUNC, int = 0); // Apply to all members of the table that match the int apply_grp (int grp_id, ACE_THR_MEMBER_FUNC func, int arg = 0); // Apply to all members of the table that match the . int apply_all (ACE_THR_MEMBER_FUNC, int = 0); // Apply to all members of the table. int join_thr (ACE_Thread_Descriptor *td, int = 0); // Join the thread described in . int resume_thr (ACE_Thread_Descriptor *td, int = 0); // Resume the thread described in . int suspend_thr (ACE_Thread_Descriptor *td, int = 0); // Suspend the thread described in . int kill_thr (ACE_Thread_Descriptor *td, int signum); // Send signal to the thread described in . int cancel_thr (ACE_Thread_Descriptor *td, int async_cancel = 0); // Set the cancellation flag for the thread described in . int register_as_terminated (ACE_Thread_Descriptor *td); // Register a thread as terminated and put it into the . ACE_Double_Linked_List thr_list_; // Keeping a list of thread descriptors within the thread manager. // Double-linked list enables us to cache the entries in TSS // and adding/removing thread descriptor entries without // affecting other thread's descriptor entries. #if !defined (VXWORKS) ACE_Double_Linked_List terminated_thr_list_; // Collect terminated but not yet joined thread entries. #endif /* VXWORKS */ ACE_Unbounded_Queue thr_to_be_removed_; // Collect pointers to thread descriptors of threads to be removed later. int grp_id_; // Keeps track of the next group id to assign. int automatic_wait_; // Set if we want the Thread_Manager to wait on all threads before // being closed, reset otherwise. // = ACE_Thread_Mutex and condition variable for synchronizing termination. #if defined (ACE_HAS_THREADS) ACE_Thread_Mutex lock_; // Serialize access to the . ACE_Condition_Thread_Mutex zero_cond_; // Keep track of when there are no more threads. #endif /* ACE_HAS_THREADS */ private: ACE_Locked_Free_List thread_desc_freelist_; #if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) static ACE_Thread_Manager *thr_mgr_; // Pointer to a process-wide . static int delete_thr_mgr_; // Must delete the if non-0. #endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ }; #if defined (ACE_THREAD_MANAGER_LACKS_STATICS) #define ACE_THREAD_MANAGER_SINGLETON_DEFINE \ ACE_Singleton; typedef ACE_Singleton ACE_THREAD_MANAGER_SINGLETON; #endif /* defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ #if defined (__ACE_INLINE__) #include "ace/Thread_Manager.i" #endif /* __ACE_INLINE__ */ #include "ace/post.h" #endif /* ACE_THREAD_MANAGER_H */