专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »编程综合 » unix并发服务器:使用 ACE 库框架在 UNIX 中开发高性能并发应用 »正文

unix并发服务器:使用 ACE 库框架在 UNIX 中开发高性能并发应用

来源: 发布时间:星期一, 2009年9月7日 浏览:0次 评论:0
  Adaptive 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 类创建个线程

   
# "ace/Thread_Manager.h" 
# <iostream> 
 
void thread_start(void* arg) 
{ 
 std::cout << "Running thread..\n"; 
} 
 
 ACE_TMAIN ( argc, ACE_TCHAR* argv) 
{ 
 ACE_Thread_Manager::instance->spawn((ACE_THR_FUNC)thread_start); 
  0; 
} 


  清单 2 给出 spawn 思路方法原型(取自 ace/Thread_Manager.h)

  清单 2. ACE_Thread_Manager::spawn 思路方法原型

   
  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, 
        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:这是生成线程优先级

   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 类创建多个线程

   
# "ace/Thread_Manager.h" 
# <iostream> 
 
void pr (void* args) 
{ 
  id = ACE_Thread_Manager::instance->thr_self; 
 std::cout << "Thread Id: " << id << std::endl; 
} 
 
 ACE_TMAIN ( argc, ACE_TCHAR* argv) 
{ 
 ACE_Thread_Manager::instance->spawn_n( 
   4, (ACE_THR_FUNC) pr, 0, THR_JOINABLE | THR_NEW_LWP); 
 
 ACE_Thread_Manager::instance->wait; 
  0; 
} 


  ACE 中种线程创建机制

  本节讨论 ACE 提供种线程创建/管理机制这种思路方法不需要对线程管理器进行显式细粒度控制在默认情况下每个进程在创建时有个线程这个线程在 开始时启动 结束时终止其他线程都需要显式地创建创建线程种方式是创建预定义 ACE_Task_Base 类子类然后覆盖 svc 思路方法新线程在 svc 思路方法中启动在 svc 思路方法返回时终止在进步解释的前请看下 清单 4 所示源代码

  清单 4. 使用 ACE_Task_Base::svc 创建线程

   
# “ace/Task.h” 
 
 Thread_1 : public ACE_Task_Base { 
 public: 
  virtual  svc( ) { 
    std::cout << “In child’s thread\n”; 
     0; 
  } 
 }; 
 
  ( ) 
{ 
  Thread_1 th1; 
  th1.activate(THR_NEW_LWP|THR_JOINABLE); 
  th1.wait; 
   0; 
} 


  在 svc 思路方法中编写和应用相关线程行为通过 activate 思路方法(在 ACE_Task_Base 类中声明和定义)执行线程在激活线程的后 等待子线程完成执行这就是 wait 思路方法作用:在 Thread_1 执行完的前主线程被阻塞等待过程是必需;否则主线程会调度子线程并执行退出在看到主线程退出时C 运行时会销毁所有子线程;因此子线程可能根本没有被调度或执行

  详细了解 ACE_Task_Base 类

  下面详细看看 ACE_Task_Base 中几个思路方法

  清单 5 给出 activate 思路方法原型

  清单 5. ACE_Task_Base::activate 思路方法原型

   
virtual  activate (long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, 
             n_threads = 1, 
             force_active = 0, 
            long priority = ACE_DEFAULT_THREAD_PRIORITY, 
             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

   n_threads:n_threads 指定要创建线程数量

   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  thread until all threads of this task are completed 
virtual  wait (void); 
 
// Suspend a task 
virtual  suspend (void); 
 
// Resume a suspended task. 
virtual  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  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  thread 
th1.resume; 
…// code continues in  thread 


  再看看线程标志

  有两种线程:内核级线程和用户级线程如果不带任何参数 activate 思路方法那么默认情况下创建内核级线程内核级线程和操作系统直接交互由内核级调度器调度和此相反用户级线程在进程范围内运行为了完成某些任务根据需要 “分配” 内核级线程THR_NEW_LWP 标志(activate 思路方法默认参数)总是确保新创建线程是内核级线程

  线程钩子

  ACE 提供个全局线程启动钩子这允许用户执行可以应用于所有线程任何操作为了创建启动钩子需要创建预定义类 ACE_Thread_Hook 子类并提供 start 思路方法定义start 接受两个参数:个用户定义指针和传递给这个用户定义 void*为了注册钩子需要静态思路方法 ACE_Thread_Hook::thread_hook见 清单 8

  清单 8. 使用全局线程钩子

   
# "ace/Task.h" 
# "ace/Thread_Hook.h" 
# <iostream> 
 
 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); 
  } 
}; 
 
 Thread_1 : public ACE_Task_Base { 
 public: 
  virtual  svc( ) { 
    std::cout << "In child's thread\n"; 
     0; 
  } 
 }; 
 
 
 ACE_TMAIN ( argc, ACE_TCHAR* argv) 
{ 
 globalHook g; 
 ACE_Thread_Hook::thread_hook(&g); 
 Thread_1 th1; 
 th1.activate; 
 th1.wait; 
  0; 
} 


  注意自动传递给启动钩子 ACE_THR_FUNC 指针是在执行线程 activate 思路方法时相同以上代码输出是:

In created thread 
In child’s thread 


  结束语

  本文简要讨论了如何使用 ACE 框架创建和管理线程ACE 框架还有其他些有用特性比如互斥、用于同步保护阻塞、共享内存和网络服务

0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: