ACE线程管理---ACE_Thread_Manager
使用ACE_Thread_Manager类进行线程管理:
虽然ACE_Task<>接口已经提供了相当丰富的的功能,但是ACE还是提供了一个工作在"幕后"的线程管理器类:ACE_Thread_Manager;这个线程管理器类用于帮助你管理ACE所创建的所有任务;这个管理器类提供了丰富的接口;ACE_Thread_Manager类还与ACE Streams框架紧密地集成在一起;
ACE允许程序员登记数量不限的退出函数(或退出仿函数functor),这些退出函数或退出仿函数将在线程退出时被自动调用,以用于进行线程退出前的"最后一秒"的清理,或者说是线程退出前的善后清理,或者是通知其它线程,某个线程的结束已经临近.退出处理器的一个优点是:它们总是会被调用,即使是线程因为调用了一个低级的ACE_Thread::exit()方法而突然退出(这个方法会使线程立即退出),也同样如此;
要设置退出functor,就必须要创建ACE_At_Thread_Exit类的一个子类,实现apply()方法,然后向ACE_Thread_Manager登记这个退出functor的一个实例.
注意:必须在退出functor所属的线程的上下文中,向线程管理器登记这个退出functor.使用ACE_Thread_Manager::at_exit()方法登记退出functor;
ACE_Thread_Manager::wait()会等待所有的子线程退出,而不管与那些线程相关联的是哪个任务,当你有不止一个任务正在执行的时候,使用这个特性将会很方便;
注意:我们要把ACE_Thread_Manager类的实例当作一个单体对象使用;其原因是:在默认情况下,ACE会通过这个单体对象来管理所有的线程;尽管在大多数情况下,你会发现默认行为已经足够,你可以创建并使用多个线程管理器对象;
线程启动挂钩:
ACE提供了一个全局的启动挂钩,可以用于拦截对线程启动函数的调用.所以,你能够针对你的应用正在使用的线程,进行任意种类的初始化.要给线程增加线程专有的数据,线程的启动挂钩是一个很好的地方;
要设置线程启动挂钩,就必须从ACE_Thread_Hook派生出来一个子类,并实现start()虚方法.这个方法的参数是一个指向线程进入点函数的指针,以及一个必须传入的void*类型的指针参数.在大多数情况下,你将执行你的特殊的启动代码,然后调用通过参数传入的进入点函数.
例如:
class MyThreadHook: public ACE_Thread_Hook
{
public:
virtual ACE_THR_FUNC_RETURN start(ACE_THR_FUNC func, void* arg)
{
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("(%t) New thread spawned\n")) );
//create the context on the thread's own stack;
ACE_TSS<SecurityContext> secCtx;
//special initialization
add_sec_context_thr(secCtx);
//call the thread-function
return (*func)(args);
}
void add_sec_context_thr(ACE_TSS<SecurityContext>& secCtx);
};
在创建了新的线程启动挂钩对象之后,需要把它设置成新线程的启动挂钩.为此,只需要调用ACE_Thread_Hook::thread_hook()静态方法,把新挂钩的一个实例传递给它;例如:
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
MyThreadHook hook;
ACE_Thread_Hook::thread_hook(&hook);
MyThread thread;
thread.active();
thread.wait();
return 0;
};
线程的取消:
取消是一种你可以用以消灭(zap)正在运行线程的途径.任何线程退出处理器都不会被调用,线程专有存储空间也不会被释放.你的线程将消失.在某些情况下,取消也是一种"必要的邪恶":为了退出一个长时间运行的、只进行计算的线程,或是终止一个阻塞在阻塞式调用上的线程.在大多数情况下,应用终止时取消线程是有意义的;
取消有以下几种模式:
A、延迟取消:
这种模式下,所有的取消操作都会被延迟到该线程的下一个取消点.取消点是代码中明确定义的点,在这个点上,线程或是已经阻塞,或是用ACE_Thread_Manager::testcancal()方法编写了显式的取消点.这种模式是用ACE构建的应用的默认模式;
B、协作式取消:
这种模式下,线程并没有被真正的取消,而是会在派生它们的ACE_Thread_Manager实例中被标记已取消.你可以调用ACE_Thread_Manager::testcalcel()方法来确定线程是否处在已取消状态.如果这样,你可以选择退出线程.这种模式避免了常规取消所带来的大多数讨厌的副作用.如果你想构建可移植的应用,就最好坚持使用这种取消模式;
C、异步取消:
这种模式下,取消操作可以在任意时刻被处理;运行在这种模式下的线程可能会难以管理.你可以把任何线程的取消状态从启用改为禁用,以确保线程不会在执行关键代码时被取消.你还可以使用线程清理处理器,它们将在线程取消时被调用,以确保线程的各不变项在取消过程中得以维持.
D、禁用取消:
调用ACE_Thread::disablecancel(),可以完全禁止取消某个线程;
ACE_Thread_Manager::cancel_task()方法可以用来取消一个线程;
下面的方法可以把线程的取消模式设置为异步取消模式:
cancel_state new_state;
new_state.cancelstate = PTHREAD_CANCEL_ENABLE;
new_state.canceltype = PTHREAD_CANCEL_ASYNCHRONOUS;
ACE_Thread::setcancelstate(new_state, 0);
关于ACE_At_Thread_Exit类的例子:
#include "ace/Log_Msg.h"
#include "ace/OS.h"
#include "ace/Thread.h"
#include "ace/Task.h"
class ExitHandler: public ACE_At_Thread_Exit
{
virtual void apply(void)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("ExitHandler::apply()-->thread %t do exiting ...\n")) );
}
};
//class CommandHandler: public ACE_Task<ACE_SYNCH>
class CommandHandler: public ACE_Task_Base
{
private:
static int nThreadNum;
ExitHandler& m_oExitHandler;
public:
CommandHandler(ExitHandler& exit): m_oExitHandler(exit)
{}
virtual int svc(void)
{
int nThreadID = 0;
int i = 0;
this->thr_mgr()->at_exit(this->m_oExitHandler);
nThreadNum++;
nThreadID = nThreadNum;
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread[%t] %d start\n"), nThreadID) );
ACE_OS::sleep(1);
while(i <= 10)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread[%t] %d print %d\n"), nThreadID, i) );
i++;
ACE_OS::sleep(1);
}
ACE_Thread::exit(4);
return nThreadID;
}
};
int CommandHandler::nThreadNum = 0;
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("Test Thread from ACE_Task_Base is running ...\n")) );
int nReturn = 0;
ExitHandler exit;
CommandHandler cmd(exit);
ACE_Thread_Manager tm;
cmd.thr_mgr(&tm);
nReturn = cmd.activate(THR_NEW_LWP);
if(nReturn != 0)
{
ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to active this thread[%d] %p\n"), nReturn, ACE_TEXT("active")) );
return -1;
}
ACE_OS::sleep(3);
ACE_DEBUG( (LM_INFO, ACE_TEXT("Suspend this thread ......\n")) );
cmd.suspend();
ACE_OS::sleep(3);
ACE_DEBUG( (LM_INFO, ACE_TEXT("Resume this thread ......\n")) );
cmd.resume();
tm.wait();
//ACE_Thread_Manager::instance()->wait();
getchar();
return 0;
}
有两种方法等待子线程的退出:
1、使用ACE_Thread_Manager类的一个单件实例来等待所有子线程退出(见蓝色代码);
如:
ACE_Thread_Manager::instance()->wait();
2、可以自定义一个ACE_Thread_Manager类的对象,并把这个对象通过ACE_Task_Base::thr_mgr()方法关联到一个线程对象上,以等待这个线程退出(见红色代码);
如:
ACE_Thread_Manager tm;
ACE_Task_Base::thr_mgr(&tm);
tm.wait();
关于ACE_Thread_Hook类的例子:
#include "ace/Log_Msg.h"
#include "ace/OS.h"
#include "ace/Thread.h"
#include "ace/Task.h"
#include "ace/Sig_Handler.h"
#include "ace/Thread_Hook.h"
class MyThreadHook: public ACE_Thread_Hook
{
public:
virtual ACE_THR_FUNC_RETURN start(ACE_THR_FUNC func, void* arg)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("%t: execute new thread hook\n")) );
return (*func)(arg);
}
};
class ExitHandler: public ACE_At_Thread_Exit
{
virtual void apply(void)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("ExitHandler::apply()-->thread %t do exiting ...\n")) );
}
};
class CommandHandler: public ACE_Task<ACE_SYNCH>
//class CommandHandler: public ACE_Task_Base
{
private:
static int nThreadNum;
ExitHandler& m_oExitHandler;
public:
CommandHandler(ExitHandler& exit): m_oExitHandler(exit)
{}
virtual int handle_signal(int signum, siginfo_t* siginfo, ucontext_t* cont)
{
if(signum == SIGUSR1)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread %t recv sig %S\n")) );
}
return 0;
}
virtual int svc(void)
{
int nThreadID = 0;
int i = 0;
this->thr_mgr()->at_exit(this->m_oExitHandler);
nThreadNum++;
nThreadID = nThreadNum;
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread[%t] %d start\n"), nThreadID) );
ACE_OS::sleep(1);
while(i <= 10)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread[%t] %d print %d\n"), nThreadID, i) );
i++;
ACE_OS::sleep(1);
}
ACE_OS::sleep(10);
ACE_Thread::exit();
return nThreadID;
}
};
int CommandHandler::nThreadNum = 0;
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
ACE_DEBUG( (LM_INFO, ACE_TEXT("Test Thread from ACE_Task_Base is running ...\n")) );
int nReturn = 0;
ExitHandler exit;
CommandHandler cmd(exit);
ACE_Thread_Manager tm;
cmd.thr_mgr(&tm);
ACE_Sig_Handler sh;
sh.register_handler(SIGUSR1, &cmd);
//set thread start hook
MyThreadHook hook;
ACE_Thread_Hook::thread_hook(&hook);
nReturn = cmd.activate(THR_NEW_LWP);
if(nReturn != 0)
{
ACE_DEBUG( (LM_ERROR, ACE_TEXT("failed to active this thread[%d] %p\n"), nReturn, ACE_TEXT("active")) );
return -1;
}
ACE_OS::sleep(3);
ACE_DEBUG( (LM_INFO, ACE_TEXT("Suspend this thread ......\n")) );
cmd.suspend();
ACE_OS::sleep(3);
ACE_DEBUG( (LM_INFO, ACE_TEXT("Resume this thread ......\n")) );
cmd.resume();
ACE_Thread_Manager::instance()->kill_grp(cmd.grp_id(), SIGUSR1);
tm.wait();
ACE_Thread_Manager::instance()->wait();
getchar();
return 0;
}
关于ACE_Thread类的例子:
#include "ace/Log_Msg.h"
#include "ace/Thread.h"
#include "ace/Thread_Manager.h"
#include "ace/OS.h"
const int THRD_NUM = 3;
struct thread_param
{
int nIdxThrd;
};
ACE_THR_FUNC_RETURN MyThrdFunc(void* param)
{
int i = 0, nThrdIdx = 0;
thread_param* lpParam = NULL;
if(param)
{
lpParam = (thread_param*)param;
nThrdIdx = lpParam->nIdxThrd;
}
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%d] start\n"), nThrdIdx) );
while(i <= 10)
{
ACE_OS::sleep(1);
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%d] is run %d\n"), nThrdIdx, i) );
i++;
}
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%d] exit\n"), nThrdIdx) );
//ACE_Thread::exit((ACE_THR_FUNC_RETURN)nThrdIdx);
return (ACE_THR_FUNC_RETURN)nThrdIdx;
}
ACE_THR_FUNC_RETURN MyThrdFunc2(void* param)
{
int i = 0;
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] start\n")) );
while(i <= 10)
{
ACE_OS::sleep(1);
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc is run %d\n"), i) );
}
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] exit")) );
return 0;
}
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
int nReturn = 0, i = 0;
ACE_thread_t tids[THRD_NUM];
ACE_hthread_t htids[THRD_NUM];
ACE_THR_FUNC_RETURN thrdExitCode = 0;
thread_param astThrdParam[THRD_NUM];
ACE_OS::memset(tids, 0, sizeof(tids));
for(i = 0; i < THRD_NUM; i++)
{
astThrdParam[i].nIdxThrd = i;
nReturn = ACE_Thread::spawn((ACE_THR_FUNC)MyThrdFunc, (void*)&astThrdParam[i], THR_NEW_LWP|THR_JOINABLE, &tids[i], &htids[i]);
}
ACE_OS::sleep(3);
ACE_Thread::suspend(htids[2]);
ACE_Thread::suspend(htids[1]);
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("thread 2 supended\n")) );
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("thread 1 supended\n")) );
ACE_OS::sleep(3);
ACE_Thread::resume(htids[1]);
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("thread 1 resume\n")) );
ACE_Thread::resume(htids[2]);
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("thread 2 resume\n")) );
getchar();
for(i = 0; i < THRD_NUM; i++)
{
ACE_Thread::join(tids[i], NULL, &thrdExitCode);
ACE_DEBUG( (LM_DEBUG, ACE_TEXT("thread %d exit with code %d\n"), i, thrdExitCode) );
}
ACE_Thread_Manager::instance()->wait();
getchar();
return 0;
}
关于ACE_Thread类的例子2:
#include "ace/Log_Msg.h"
#include "ace/Thread.h"
#include "ace/Thread_Manager.h"
#include "ace/OS.h"
const int THRD_NUM = 3;
struct thread_param
{
int nIdxThrd;
};
ACE_THR_FUNC_RETURN MyThrdFunc(void* param)
{
int i = 0;
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] start\n")) );
while(i <= 10)
{
ACE_OS::sleep(1);
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] is run %d\n"), i) );
i++;
}
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] exit\n")) );
return 0;
}
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
size_t spawnRet = 0;
ACE_thread_t tids[THRD_NUM];
ACE_hthread_t htids[THRD_NUM];
ACE_THR_FUNC_RETURN thrdExitCode = 0;
thread_param astThrdParam[THRD_NUM];
spawnRet = ACE_Thread::spawn_n((size_t)THRD_NUM, (ACE_THR_FUNC)MyThrdFunc);
spawnRet = ACE_Thread::spawn_n(tids, (size_t)THRD_NUM, (ACE_THR_FUNC)MyThrdFunc, NULL, THR_NEW_LWP|THR_JOINABLE);
ACE_Thread_Manager::instance()->wait();
getchar();
return 0;
}
关于ACE_Thread_Manager类的例子:
#include "ace/Log_Msg.h"
#include "ace/Thread.h"
#include "ace/Thread_Manager.h"
#include "ace/OS.h"
const int THRD_NUM = 3;
struct thread_param
{
int nIdxThrd;
};
ACE_THR_FUNC_RETURN MyThrdFunc(void* param)
{
int i = 0;
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] start\n")) );
while(i <= 10)
{
ACE_OS::sleep(1);
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] is run %d\n"), i) );
i++;
}
ACE_DEBUG( (LM_INFO, ACE_TEXT("thread MyThrdFunc[%t] exit\n")) );
return 0;
}
int ACE_TMAIN(int argc, ACE_TCHAR** argv)
{
int nReturn = 0;
size_t spawnRet = 0;
ACE_thread_t tids[THRD_NUM];
ACE_Thread_Manager* lpThrdMgr = ACE_Thread_Manager::instance();
nReturn = lpThrdMgr->spawn((ACE_THR_FUNC)MyThrdFunc);
spawnRet = lpThrdMgr->spawn_n((size_t)THRD_NUM, (ACE_THR_FUNC)MyThrdFunc);
spawnRet = lpThrdMgr->spawn_n(tids, (size_t)THRD_NUM, (ACE_THR_FUNC)MyThrdFunc, NULL, THR_NEW_LWP|THR_JOINABLE);
lpThrdMgr->wait();
getchar();
return 0;
}