我所接触的ACE中对线程操作的类主要有两个,一个是ACE_Thread,另一个为ACE_Thread_Manager
ACE_Thread能够管理所有线程,只要你掌握有需要被管理的线程的ID;ACE_Thread_Manager的一个对象能够管理该对象所创建的线程。
一个线程可以通过传入THR_JOINABLE属性来创建,从而可以在其他线程(并不一定要是创建该线程的线程或者主线程)等待该线程结束、捕获该线程函数的返回值、回收该线程资源;也可以通过传入THR_DETACHED属性来使得被创建的线程自动在线程函数结束后释放资源,这种线程无法在其他线程中等待它的结束。
创建一个线程的函数有:
/*通过ACE_Thread类中的函数创建一个线程
*CreateFunc为自己定义的一个全局函数原型为void CreateFunc(TestTask* p)
*&test为线程函数需要传入的参数TestTask* p
*THR_NEW_LWP | THR_DETACHED 指定线程的属性,该线程属于能够自动释放资源的那种,至于THR_NEW_LWP的含义,我想大概是指创建一个轻量级线程的意思,可以参考一下http://www.linuxsir.org/bbs/printthread.php?t=55674
*最后用一个变量nThreadId来接受被创建的线程的线程ID
*/
ACE_Thread::spawn((ACE_THR_FUNC)CreateFunc,&test, THR_NEW_LWP | THR_DETACHED,&nThreadId);
/*通过ACE_Thread_Manager的对象创建线程,pThreadManager为ACE_Thread_Manager的一个指针
*spawn函数的形参的意义都一样
*THR_JOINABLE 表示被创建的线程需要通过其他线程调用join方法来释放资源,并可以通过pThreadManager->join(nthreadId)来等待线程结束
*THR_SUSPENDED代表线程可以被挂起,但是并不是创建时传入了该属性的线程就能挂起,我的那个线程函数MyThread::func就没法被挂起,还望高手指点
*/
pThreadManager->spawn((ACE_THR_FUNC)MyThread::func,NULL, THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED|THR_SUSPENDED,&m_nThreadId)
代码:
#include "ace/Thread.h"
#include "ace/Thread_Manager.h"
#include "ace/Task.h"
#include "ace/Reactor.h"
#include <iostream>
using namespace std;
class MyThread
{
public:
static int func()
{
int count = 1000;
for(int i=0;i<count;i++)
{
cout<<"Enter Thread Func"<<i<<endl;
if ( i%50 == 1 )
ACE_OS::sleep(1);
}
return 0;
}
};
class TestTask : public ACE_Task<ACE_MT_SYNCH>
{
public:
TestTask():ACE_Task<ACE_MT_SYNCH>(new ACE_Thread_Manager)
{
reactor(new ACE_Reactor);
m_nThreadId= 0;
activate();
}
long Create()
{
cout<<"Spawn Thread Return:"<<thr_mgr()->spawn((ACE_THR_FUNC)MyThread::func,NULL, THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED|THR_SUSPENDED,&m_nThreadId)<<endl;
cout<<"Create Thread Id="<<m_nThreadId<<endl;
return m_nThreadId;
}
int Suspend()
{
return thr_mgr()->suspend(m_nThreadId);
}
int Resume()
{
return thr_mgr()->resume(m_nThreadId);
}
void Stop()
{
cout<<"Join Thread Return:"<<thr_mgr()->join(m_nThreadId)<<endl;
}
int svc()
{
reactor()->owner(ACE_Thread::self());
reactor()->run_reactor_event_loop();
return 0;
}
ACE_thread_t m_nThreadId;
};
void CreateFunc(TestTask* p)
{
//while(1)
{
p->Create();
//ACE_OS::sleep(5);
}
}
void JoinFunc(TestTask* p)
{
p->Stop();
}
int main()
{
TestTask test;
ACE_thread_t nThreadId = 0;
ACE_Thread::spawn((ACE_THR_FUNC)CreateFunc,&test, THR_NEW_LWP | THR_DETACHED,&nThreadId);
ACE_OS::sleep(1);
cout<<test.Suspend()<<endl;
cout<<"OK"<<endl;
int a;
cin>>a;
cout<<test.Resume()<<endl;
cout<<"main join:"<<ACE_Thread::join(nThreadId)<<endl;
ACE_OS::sleep(3);
ACE_Thread::spawn((ACE_THR_FUNC)JoinFunc,&test, THR_NEW_LWP | THR_JOINABLE,&nThreadId);
cout<<ACE_Thread::join(nThreadId)<<endl;
while(1)
ACE_OS::sleep(1);
return 0;
}
posted @ 2012-02-12 23:16 jingshaq 阅读(136) 评论(0) 编辑
使用ACE_Task_Base类来对线程进行管理:
我们可以把线程的各种属性标志作为参数传递给ACE_Task_Base::active()方法,这样就可以创建具有某种或某些特殊属性的线程了;这些属性定义了线程将怎样被创建、调度、销毁等等;
线程创建标志:
THR_CANCEL_DISABLE : 不允许这个线程被取消;
THR_CANCEL_ENABLE : 允许这个线程被取消;
THR_CANCEL_DEFERRED: 只允许延迟的取消;
THR_BOUND : 创建一个线程,并绑定到一个可由内核调度的实体上;
THR_NEW_LWP : 创建一个内核级线程;该标志影响进程的并发属性;对"未绑定线程"来说,其预想的并发级别是增1,也就是添加一个新的内核线程到可用的线程池中,以运行用户线程;在不支持N:M混合线程模型的OS平台上,该标志会被忽略;
THR_DETACHED : 创建一个分离的线程;这就意味着这个线程的退出状态不能被其它线程访问;当这个线程退出的时候,其线程ID和它所占用的资源会被OS自动回收;
THR_JOINABLE : 允许新创建的线程被"会合(join)";这就意味着这个线程的退出状态能够被其它线程访问,可以通过join()方法来访问它的退出状态,但是它的线程ID和它所占用的资源不会被OS回收;所有ACE线程创建方法的默认行为都是THR_JOINABLE;
THR_SUSPENDED : 创建一个线程,但让其处在挂起状态;
THR_DAEMON : 创建一个看守(daemon)线程;
THR_SCHED_FIFO : 如果可用,使用FIFO政策调度新创建的线程;
THR_SCHED_RR : 如果可用,使用round-robin方案调度新创建的线程;
THR_SCHED_DEFAULT : 使用操作系统上可用的无论哪种默认调度方案;
THR_SCOPE_SYSTEM : 新线程在系统调度争用空间中创建,永久绑定于新创建的内核线程;
THR_SCOPE_PROCESS : 新线程在进程调度争用空间中创建,也就是说,它将作为一个用户线程运行;
线程的这些属性标志通过逻辑或运算符"|"串在一起,并把它作为ACE_Task_Base::active()方法的第一个参数传递给该方法;如:
ACE_Task_Base:active(THR_NEW_LWP | THR_SCHED_DEFAULT | THR_SUSPENDED | THR_JOINABLE);
调度竞争范围:
大多数OS都在内核级线程和用户级线程之间作出了区分;内核级线程是这样的可调度实体:OS知道它们,并且会通过内核级的调度器对它们进行调度.而另一方面,用户级线程是量级更轻的线程,由基于库的调度器在进程的地址空间中对其进行调度.这样的线程允许速度更快的上下文切换,但是可能会被阻塞.作为程序员,你只能处理用户级线程.你的进程会得到一个内核线程池,用于调度你所有的用户级线程;你可以使用THR_BOUND标志显式地把一个用户级线程绑定到一个特定的内核线程上去;这样被绑定的用户级线程的调度就会使用底层的内核级线程来完成;
如果你指定要在创建线程时使用THR_NEW_LWP标志,那么,你可以确信,一个新的内核级可调度实体也将被创建;也就是说,这个新的用户级线程被绑定到一个新的内核级线程上;这是ACE_Task_Base::active()方法的默认行为;但是,如果你指定了自己的属性标志参数,并且没有包含THR_NEW_LWP标志,那么线程库就会创建一个用户级线程;
一旦ACE_Task_Base::active()方法返回,OS就已经创建了一个新的线程了;但是,这并没有说明关于新线程的当前运行状态的任何情况;OS会使用其特有的某种内部调度方案来决定何时运行新线程.所以,即使线程已经创建,当active()方法返回时,它也未必就在运行;
通过指定THR_SUSPENDED标志,你可以在一定程度上控制线程的初始运行状态.这个标志会使OS创建处在挂起状态的新线程;你可以调用resume()方法来激活这个处于挂起状态的新线程而让它开始运行;
线程的优先级和调度类:
大多数OS都会以自己的方式来定义线程的优先级;例如:Solaris定义的优先级范围是0--127,127是最高优先级;Windows定义的优先级范围是0--15,15是最高优先级;而VxWorks定义的优先级是0--255,0是最高优先级;
大多数通用OS都只提供了一种分时调度类;分时调度器尝试以这样的方式来保证公平性:优先级最高的线程能够执行一段有限的时间(称为时间片:time slice).如果在正在执行的线程用完其时间片之前,有优先级更高的线程变得可以运行,则优先级较低的线程就会被占先,而优先级较高的线程会开始使用其时间片;
还有些OS实现了实时调度类;在支持分时调度类的OS中,实时调度类中的线程所处的优先级总是比分时类中的任何线程的优先级都要高;换句话说,在同时支持分时调度类和实时调度类的OS中,实时调度类中的所有线程的优先级都比分时调度类中的线程的优先级要高;
在实时调度类中提供了两种调度政策:
A、round-robin:由一个时间量指定、在被同一优先级的其它实时线程占先之前、某个线程所能运行的最大时间;
B、先进先出(FIFO):优先级最高的的线程可以随意运行任意长的时间,直到它自愿让出CPU控制权,或被优先级更高的实时线程占先为止;
线程优先级宏:
ACE_THR_PRI_OTHER_MIN: 分时调度类的最低优先级;
ACE_THR_PRI_OTHER_DEF: 分时调度类的默认优先级;
ACE_THR_PRI_OTHER_MAX: 分时调度类的最高优先级;
ACE_THR_PRI_RR_MIN : 采用round-robin调度政策的实时调度类的最低优先级;
ACE_THR_PRI_RR_DEF : 采用round-robin调度政策的实时调度类的默认优先级;
ACE_THR_PRI_RR_MAX : 采用round-robin调度政策的实时调度类的最高优先级;
ACE_THR_PRI_FIFO_MIN : 采用FIFO调度政策的实时调度类的最低优先级;
ACE_THR_PRI_FIFO_DEF : 采用FIFO调度政策的实时调度类的默认优先级;
ACE_THR_PRI_FIFO_MAX : 采用FIFO调度政策的实时调度类的最高优先级;
我们在使用这些优先级的时候,要确保这些优先级参数能在所使用的OS平台上正确工作;如果没有指定调度类,那么默认使用的就是分时调度类,也称为"其它";
注意:你必须自己负责设置能在你的应用中正确工作的线程优先级.在这个问题上,ACE没有提供多少帮助;你一定要确保传递给active()方法的值的工作方式正是你想要的;
线程池:
ACE_Task_Base类和ACE_Task<T>类模板的active()方法不但可以创建单个线程,而且也可以一次性地创建多个线程,所有这些线程都是从同一个svc()方法进入点开始执行;在创建一个任务内的一组线程的时候,ACE会在内部把一个组标识符赋值给任务内的所有线程,可以通过grp_id()方法来访问它,并用于后续的组管理操作;这样创建的所有线程共享同一个ACE_Task_Base类的对象会者是共享同一个ACE_Task<>类的对象,但是这组线程中的每个线程都拥有自己独立的栈资源;
必须注意:在使用线程组的时候,不要让线程组中的所有工作线程都锁在同一个资源上,以致于事情变得更糟糕;因为加锁开销可能会高得足以抵消使用多线程所获得的任何性能上的提高;
posted @ 2012-02-12 23:15 jingshaq 阅读(215) 评论(0) 编辑
一次创建多个相同线程
// Create 4 threads.
handler.activate (THR_NEW_LWP | THR_JOINABLE, 4);
handler.wait ();
使用ACE_Thread_Manager进行线程管理
这个管理器(ACE_Thread_Manager)提供了一个丰富的接口,组管理、创建、状态获取、线程启动挂钩和退出挂钩,and so on。
线程退出挂钩(“最后一秒”的清理)
它总是会被调用,即使你调用了低级的ACE_Thread::exit()突然退出。
只需要创建ACE_At_Thread_Exit的之类,重载apply()虚方法(do something you want),然后向ACE_Thread_Manager登记这个类的一个实例。
#include <ace/Task.h>
#include <ace/Log_Msg.h>
class ExitHandler : public ACE_At_Thread_Exit
{
public:
virtual void apply (void)
{
ACE_DEBUG((LM_INFO,
ACE_TEXT ("(%t) is exiting \n")));
// Shut down all devices.
}
};
class HA_CommandHandler : public ACE_Task_Base
{
private:
ExitHandler& eh_;
public:
HA_CommandHandler(ExitHandler& eh) : eh_(eh)
{ }
virtual int svc (void)
{
ACE_DEBUG((LM_DEBUG,
ACE_TEXT("(%t) starting up \n")));
this->thr_mgr()->at_exit(eh_);
// Do something.
// Forcefully exit.
ACE_Thread::exit();
// NOT REACHED
return 0;
}
};
int ACE_TMAIN (int, ACE_TCHAR *[])
{
ExitHandler eh;
ACE_Thread_Manager tm;
HA_CommandHandler handler(eh);
handler.thr_mgr(&tm);
handler.activate();
tm.wait();
return 0;
}
线程启动挂钩
ACE提供了一个全局的启动挂钩,可用于拦截对线程启动函数的调用(所有线程)。
从ACE_Thread_Hook派生一个子类,重载start()虚方法。
#include <ace/Log_Msg.h>
#include <ace/Thread_Hook.h>
#include <ace/Task.h>
class HA_ThreadHook : 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);
return (*func)(arg);
}
//void add_sec_context_thr(ACE_TSS<SecurityContext> &secCtx);
};
int ACE_TMAIN(int, ACE_TCHAR *[])
{
HA_ThreadHook hook;
ACE_Thread_Hook::thread_hook(&hook);
ACE_Task_Base handler;
handler.activate();
handler.wait();
return 0;
}
信号(Signals)
由于在Windows平台上面,略。
取消(Cancellation)
取消(Cancellation)是一种你可以用消灭(zap)正在运行的线程的途经。任何线程退出处理器都不会被调用;线程专有存储(thread-specific storage )也不会被释放。
除了协作式取消(cooperative cancellation),你最好避免使用取消功能,除非你认为真的有必要使用他们。
取消的若干模式:
1)延迟的取消(Deferred cancelability)
2)协作式取消(cooperative cancellation)
线程并没有真的被取消,而是会在派生它们的ACE_Thread_Manager 实例中被标记为已取消,你可以调用ACE_Thread_Manager::testcancel() 来确定线程是否处在已取消状态,----如果是这样,你可以选择退出线程。
3)异步取消(Asynchronous cancelability)
4)禁用(Disabled)
用ACE_Thread::disablecancel() 可以完全禁止取消某个线程。
//协作式取消(cooperative cancellation)
#include <ace/OS.h>
#include <ace/Log_Msg.h>
#include <ace/Task.h>
#include <ace/Thread_Manager.h>
class CanceledTask : public ACE_Task<ACE_MT_SYNCH>
{
public:
virtual int svc(void)
{
ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%t) starting up \n")));
// Cache our ACE_Thread_Manager pointer.
ACE_Thread_Manager* mgr = this->thr_mgr();
while (1)
{
if (mgr->testcancel(mgr->thr_self()))
return 0;
ACE_Message_Block* mb;
ACE_Time_Value tv(0, 1000);
tv += ACE_OS::time(0);
int result = this->getq(mb, &tv);
if (result == -1 && errno == EWOULDBLOCK)
continue;
else
{
// Do real work.
}
}
return 0;
}
};
int ACE_TMAIN(int, ACE_TCHAR *[])
{
CanceledTask task;
task.activate();
ACE_OS::sleep(1);
ACE_Thread_Manager::instance()->cancel_task(&task);
task.wait();
return 0;
}
posted @ 2012-02-12 23:15 jingshaq 阅读(203) 评论(0) 编辑
http://www.ibm.com/developerworks/cn/aix/library/au-ace/
daptive Communication Environment (ACE) 是一个高性能、开放源码、面向对象的框架和 C++
类库,它有助于简化网络应用程序的开发。ACE 工具包包括一个操作系统层和一个封装网络 API 的 C++
外观(facades)集合。本文讨论如何使用 ACE 线程设计高性能、并发、面向对象的网络应用程序。对 ACE 的完整说明,包括如何下载和安装这个工具包,请参见 参考资料。
用于创建和管理线程的 ACE 类
在进程中生成和管理多个线程涉及下面的类:
ACE_Thread_Manager
:这是负责创建、管理和同步线程的主要的类。每种操作系统在处理线程方面有细微差异,这个类对应用程序开发人员隐藏这些差异。ACE_Sched_Params
:使用这个类管理各个线程的调度优先级,调度优先级是在 ACE 源代码发行版的 ace/Sched_Params.h 头文件中定义的。可以采用不同的调度策略,可以是 “先到先服务” 的循环方式。ACE_TSS
:在多线程应用程序中使用全局变量会导致同步问题。ACE_TSS
类提供与线程相关的存储模式,可以对那些对于程序是全局的,但是对于每个线程私有的数据提供抽象。ACE_TSS
类提供 operator()
方法,这个方法提供与线程相关的数据。回页首
了解线程管理器类
原生操作系统线程 API 是不可移植的:存在语法和语义差异。例如,UNIX® pthread_create()
和 Windows® CreateThread()
方法都创建线程,但是语法不一样。ACE_Thread_Manager
类提供以下功能:
表 1 介绍 ACE_Thread_Manager
类的重要方法。
表 1. ACE_Thread_Manager 类的方法
方法名 | 说明 |
---|---|
instance |
ACE_Thread_Manager 类是一个单实例类,使用这个方法访问线程管理器的惟一实例。 |
spawn |
这个方法创建一个新线程,它的一个输入参数是 C/C++ 函数指针,这个函数执行应用程序的特定工作。 |
exit |
这个方法终止一个线程,释放这个线程的所有资源。 |
spawn_n |
这个方法创建属于同一个线程组的多个线程。 |
close |
这个方法关闭已经创建的所有线程并释放它们的资源。 |
suspend |
线程管理器暂停指定的线程。 |
resume |
线程管理器恢复执行前面暂停的线程。 |
使用 ACE_Thread_Manager 类的变体
可以作为单实例类使用 ACE_Thread_Manager
类,也可以创建这个类的多个实例。对于单一实例,通过调用 instance
方法访问实例。如果需要管理多个线程组,可以创建不同的线程管理器类,每个类控制它自己的线程集。
清单 1 中的示例创建一个线程。
清单 1. 使用 ACE_Thread_Manager 类创建一个线程
#include "ace/Thread_Manager.h" #include <iostream> void thread_start(void* arg) { std::cout << "Running thread..\n"; } int ACE_TMAIN (int argc, ACE_TCHAR* argv[]) { ACE_Thread_Manager::instance()->spawn((ACE_THR_FUNC)thread_start); return 0; } |
清单 2 给出 spawn()
方法的原型(取自 ace/Thread_Manager.h)。
清单 2. ACE_Thread_Manager::spawn 方法的原型
int spawn (ACE_THR_FUNC func, void *arg = 0, long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, ACE_thread_t *t_id = 0, ACE_hthread_t *t_handle = 0, long priority = ACE_DEFAULT_THREAD_PRIORITY, int grp_id = -1, void *stack = 0, size_t stack_size = ACE_DEFAULT_THREAD_STACKSIZE, const char** thr_name = 0); |
对于初学者来说,创建线程需要的参数数量似乎太多了,所以我们详细讨论一下各个参数和它们的作用:
ACE_THR_FUNC func
:这是在生成线程时调用的函数。void* arg
:这是在生成线程时调用的函数的参数。void*
意味着用户可以传递应用程序特有的任何数据类型,甚至可以使用某种结构把多个参数组合成单一数据。long flags
:使用 flags
变量设置生成的线程的几个属性。各个属性都由单一位表示,按照 “或” 关系组合在一起。表 2 说明一些属性。ACE_thread_t *t_id
:使用这个函数访问创建的线程的 ID。每个线程具有惟一的 ID。long priority
:这是生成的线程的优先级。int grp_id
:如果提供这个参数,那么它表示生成的线程是否属于现有的某一线程组。如果传递 -1
,那么创建新的线程组并在这个组中添加生成的线程。void* stack
:这是预先分配的堆栈区域的指针。如果提供 0
,就请求操作系统提供生成的线程的堆栈区域。size_t stack_size
:这个参数指定线程堆栈的大小(字节数)。如果对于前一个参数(堆栈指针)指定了 0
,那么请求操作系统提供大小为 stack_size
的堆栈区域。const char** thr_name
:这个参数只与支持线程命名的平台(比如 VxWorks)相关。对于 UNIX 平台,在大多数情况下忽略它。
表 2. 线程属性及其说明
线程创建标志 | 说明 |
---|---|
THR_CANCEL_DISABLE |
不允许取消这个线程。 |
THR_CANCEL_ENABLE |
允许取消这个线程。 |
THR_DETACHED |
创建异步线程。线程的退出状态对于其他任何线程不可用。当线程终止时,操作系统回收线程资源。 |
THR_JOINABLE |
允许新线程的退出状态对于其他线程可用。这也是 ACE 创建的线程的默认属性。当这种线程终止时,操作系统不回收线程资源,直到其他线程联结它为止。 |
THR_NEW_LWP |
创建显式的内核级线程(而不是用户级线程)。 |
THR_SUSPENDED |
创建处于暂停状态的新线程。 |
清单 3 中的示例使用线程管理器类的 spawn_n
方法创建多个线程。
清单 3. 使用 ACE_Thread_Manager 类创建多个线程
#include "ace/Thread_Manager.h" #include <iostream> void print (void* args) { int id = ACE_Thread_Manager::instance()->thr_self(); std::cout << "Thread Id: " << id << std::endl; } int ACE_TMAIN (int argc, ACE_TCHAR* argv[]) { ACE_Thread_Manager::instance()->spawn_n( 4, (ACE_THR_FUNC) print, 0, THR_JOINABLE | THR_NEW_LWP); ACE_Thread_Manager::instance()->wait(); return 0; } |
回页首
ACE 中的另一种线程创建机制
本节讨论 ACE 提供的另一种线程创建/管理机制。这种方法不需要对线程管理器进行显式的细粒度的控制。在默认情况下,每个进程在创建时有一个线程,这个线程在 main
函数开始时启动,在 main
结束时终止。其他线程都需要显式地创建。创建线程的另一种方式是创建预定义的 ACE_Task_Base
类的子类,然后覆盖 svc()
方法。新线程在 svc()
方法中启动,在 svc()
方法返回时终止。在进一步解释之前,请看一下 清单 4 所示的源代码。
清单 4. 使用 ACE_Task_Base::svc 创建线程
#include “ace/Task.h” class Thread_1 : public ACE_Task_Base { public: virtual int svc( ) { std::cout << “In child’s thread\n”; return 0; } }; int main ( ) { Thread_1 th1; th1.activate(THR_NEW_LWP|THR_JOINABLE); th1.wait(); return 0; } |
在 svc()
方法中编写与应用程序相关的线程行为。通过调用 activate()
方法(在 ACE_Task_Base
类中声明和定义)执行线程。在激活线程之后,main()
函数等待子线程完成执行。这就是 wait()
方法的作用:在 Thread_1
执行完之前,主线程被阻塞。这一等待过程是必需的;否则,主线程会调度子线程并执行退出。在看到主线程退出时,C
运行时会销毁所有子线程;因此,子线程可能根本没有被调度或执行。
详细了解 ACE_Task_Base 类
下面详细看看 ACE_Task_Base
中的几个方法。
清单 5 给出 activate()
方法的原型。
清单 5. ACE_Task_Base::activate 方法的原型
virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, int n_threads = 1, int force_active = 0, 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, ACE_thread_t thread_ids[ ] = 0, const char* thr_name[ ] = 0); |
可以使用 activate()
方法创建一个或多个线程,每个线程调用相同的 svc()
方法,所有线程采用相同的优先级并具有相同的组 ID。下面简要介绍一些输入参数:
long flags
:参见 表 2。int n_threads
:n_threads
指定要创建的线程的数量。int force_active
:如果这个标志是 True,而且存在这个任务已经生成的线程,那么新生成的所有线程会共享以前生成的线程的组 ID,忽略传递给 activate()
方法的值。long priority
:这个参数指定线程或线程集合的优先级。调度优先级值是与操作系统相关的,坚持使用默认值ACE_DEFAULT_THREAD_PRIORITY
是最安全的。ACE_hthread_t thread_handles
:如果 thread_handles
不是零,那么在生成 n 个线程之后,会把各个线程句柄赋值给这个数组。void* stack
:如果指定这个参数,它指定一个指针数组,这些指针指向各个线程的堆栈基。size_t stack_size
:如果指定这个参数,它指定一个整数数组,这些整数表示各个线程堆栈的大小。ACE_thread_t thread_ids
:如果 thread_ids
不是零,那么这个参数是一个数组,其中包含 n 个新生成的线程的 ID。 清单 6 给出 ACE_Task_Base
类中另外几个有用的例程。
清单 6. ACE_Task_Base 中的其他例程
// Block the main thread until all threads of this task are completed virtual int wait (void); // Suspend a task virtual int suspend (void); // Resume a suspended task. virtual int resume (void); // Gets the no. of active threads within the task size_t thread_count (void) const; // Returns the id of the last thread whose exit caused the thread count // of this task to 0. A zero return status implies that the result is // unknown. Maybe no threads are scheduled. ACE_thread_t last_thread (void) const; |
为了创建处于暂停状态的线程(而不是通过调用 suspend()
方法显式地暂停),需要向 activate()
方法传递 THR_SUSPENDED
标志。可以通过调用 resume()
方法恢复执行线程,见 清单 7。
清单 7. 暂停线程和恢复执行
Thread_1 th1; th1.activate(THR_NEW_LWP|THR_JOINABLE|THR_SUSPENDED); …// code in the main thread th1.resume(); …// code continues in main thread |
再看看线程标志
有两种线程:内核级线程和用户级线程。如果不带任何参数调用 activate()
方法,那么默认情况下创建内核级线程。内核级线程与操作系统直接交互,由内核级调度器调度。与此相反,用户级线程在进程范围内运行,为了完成某些任务,根据需要 “分配” 内核级线程。THR_NEW_LWP
标志(activate()
方法的默认参数)总是确保新创建的线程是内核级线程。
线程钩子
ACE 提供一个全局的线程启动钩子,这允许用户执行可以应用于所有线程的任何操作。为了创建启动钩子,需要创建预定义类ACE_Thread_Hook
的子类并提供 start()
方法定义。start()
接受两个参数:一个用户定义函数的指针和传递给这个用户定义函数的void*
。为了注册钩子,需要调用静态方法 ACE_Thread_Hook::thread_hook
,见 清单 8。
清单 8. 使用全局线程钩子
#include "ace/Task.h" #include "ace/Thread_Hook.h" #include <iostream> class globalHook : public ACE_Thread_Hook { public: virtual ACE_THR_FUNC_RETURN start (ACE_THR_FUNC func, void* arg) { std::cout << "In created thread\n"; (*func)(arg); } }; class Thread_1 : public ACE_Task_Base { public: virtual int svc( ) { std::cout << "In child's thread\n"; return 0; } }; int ACE_TMAIN (int argc, ACE_TCHAR* argv[]) { globalHook g; ACE_Thread_Hook::thread_hook(&g); Thread_1 th1; th1.activate(); th1.wait(); return 0; } |
注意,自动传递给启动钩子的 ACE_THR_FUNC
指针是在执行线程的 activate()
方法时调用的相同函数。以上代码的输出是:
In created thread In child’s thread |
结束语
本文简要讨论了如何使用 ACE 框架创建和管理线程。ACE 框架还有其他一些有用的特性,比如互斥、用于同步的保护阻塞、共享内存和网络服务。