ACL库开发出高并发半驻留式线程池程序
来源:优易学  2011-12-19 16:17:49   【优易学:中国教育考试门户网】   资料下载   IT书店
  一、概述
  在当今强调多核开发的年代,要求程序员能够写出高并发的程序,而利用多个核一般有两种方式:采用多线程方式或多进程方式。每处理一个新任务时如果临时产生一个线程或进程且处理完任务后线程或进程便立即退出,显示这种方式是非常低效的,于是人们一般采用线程池的模型(这在JAVA或 .NET 中非常普遍)或多进程进程池模型(这一般在UNIX平台应用较多)。此外,对于线程池或进程池模型又分为两种情形:常驻留内存或半驻留内存,常驻内存是指预先产生一批线程或进程,等待新任务到达,这些线程或进程即使在空闲状态也会常驻内存;半驻留内存是指当来新任务时如果线程池或进程池没有可利用线程或进程则启动新的线程或进程来处理新任务,处理完后,线程或进程并不立即退出,而是空闲指定时间,如果在空闲阀值时间到达前有新任务到达则立即处理新任务,如果到达空闲超时后依然没有新任务到达,则这些空闲的线程或进程便退出,以让出系统资源。所以,对比常驻内存方式和半驻留内存方式,不难看出半驻留方式更有按需分配的意味。
  下面仅以ACL框架中的半驻留线程池模型为例介绍了如何写一个半驻留线程池的程序。
  二、半驻留线程池例子
  2.1)程序代码
  #include "lib_acl.h"
  #include <assert.h>
  /**
  * 用户自定义数据结构
  */
  typedef struct THREAD_CTX {
  int i;
  } THREAD_CTX;
  /* 全局性静态变量 */
  static ACL_WORK_QUEUE *__wq = NULL;
  /* 线程局部存储变量(C99支持此种方式声明,方便许多) */
  static __thread unsigned int __local = 0;
  static void workq_thread_fn(int event acl_unused, void *arg)
  {
  ACL_WORKER_ATTR *worker_attr = (ACL_WORKER_ATTR*) arg; /* 获得当前工作线程的属性变量 */
  THREAD_CTX *ctx = (THREAD_CTX*) worker_attr->run_data; /* 获得用户自定义对象 */
  int i = 5;
  while (i-- > 0) {
  printf("thread start! tid=%d, i=%d, __local=%d\r\n",
  acl_pthread_self(), ctx->i, __local);
  /* 在本线程中将线程局部变量加1 */
  __local++;
  sleep(1);
  }
  acl_myfree(ctx);
  /* 至此,该工作线程进入空闲状态,直到空闲超时退出 */
  }
  static int __on_thread_init(void *arg, ACL_WORKER_ATTR *attr)
  {
  const char *myname = "__on_thread_init";
  ACL_WORK_QUEUE *wq = (ACL_WORK_QUEUE*) arg;
  /* 判断一下,仅是为了验证参数传递过程 */
  assert(wq == __wq);
  printf("%s: thread(%d) init now\r\n", myname, acl_pthread_self());
  /* 返回0表示继续执行该线程获得的新任务,返回-1表示停止执行该任务 */
  return (0);
  }
  static void __on_thread_exit(void *arg, ACL_WORKER_ATTR *attr)
  {
  const char *myname = "__on_thread_exit";
  ACL_WORK_QUEUE *wq = (ACL_WORK_QUEUE*) arg;
  /* 判断一下,仅是为了验证参数传递过程 */
  assert(wq == __wq);
  printf("%s: thread(%d) exit now\r\n", myname, acl_pthread_self());
  }
  static void run_thread_pool(ACL_WORK_QUEUE *wq)
  {
  THREAD_CTX *ctx; /* 用户自定义参数 */
  /* 设置全局静态变量 */
  __wq = wq;
  /* 设置线程开始时的回调函数 */
  (void) acl_workq_atinit(wq, __on_thread_init, wq);
  /* 设置线程退出时的回调函数 */
  (void) acl_workq_atfree(wq, __on_thread_exit, wq);
  ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX));
  assert(ctx);
  ctx->i = 0;
  /**
  * 向线程池中添加第一个任务,即启动第一个工作线程
  * @param wq 线程池句柄
  * @param workq_thread_fn 工作线程的回调函数
  * @param event_type 此处写0即可
  * @param ctx 用户定义参数
  */
  acl_workq_add(wq, workq_thread_fn, 0, ctx);
  sleep(1);
  ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX));
  assert(ctx);
  ctx->i = 1;
  /* 向线程池中添加第二个任务,即启动第二个工作线程 */
  acl_workq_add(wq, workq_thread_fn, 0, ctx);
  }
  int main(int argc acl_unused, char *argv[] acl_unused)
  {
  ACL_WORK_QUEUE *wq;
  int max_threads = 20; /* 最多并发20个线程 */
  int idle_timeout = 10; /* 每个工作线程当空闲10秒后自动退出 */
  /* 创建半驻留线程句柄 */
  wq = acl_workq_create(max_threads, idle_timeout, NULL, NULL);
  assert(wq);
  run_thread_pool(wq);
  /* 主线程等待用户在终端输入任意字符后退出 */
  getchar();
  /* 销毁线程池对象 */
  acl_workq_destroy(wq);
  return (0);
  }
  2.2)编译链接
  从 http://www.sourceforge.net/projects/acl/ 站点下载 acl_project 代码,在WIN32平台下请用VC2003编译,打开 acl_project\win32_build\vc\acl_project_vc2003.sln 编译后在目录 acl_project\dist\lib_acl\lib\win32 下生成lib_acl_vc2003.lib, 然后在示例的控制台工程中包含该库,并包含acl_project\lib_acl\include 下的 lib_acl.h 头文件,编译上述源代码即可。
  另外,还可以查看ACL的在线帮助文档:http://acl.sourceforge.net/acl_help/index.html
  2.3) 运行
  运行示例程序后,在我的机器的显示结果如下:
  __on_thread_init: thread(14016) init now
  thread start! tid=14016, i=0, __local=0
  thread start! tid=14016, i=0, __local=1
  __on_thread_init: thread(8792) init now
  thread start! tid=8792, i=1, __local=0
  thread start! tid=14016, i=0, __local=2
  thread start! tid=8792, i=1, __local=1
  thread start! tid=8792, i=1, __local=2
  thread start! tid=14016, i=0, __local=3
  thread start! tid=14016, i=0, __local=4
  thread start! tid=8792, i=1, __local=3
  thread start! tid=8792, i=1, __local=4
  __on_thread_exit: thread(14016) exit now
  __on_thread_exit: thread(8792) exit now

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训