QNX之编写资源管理器(九)

QNX相关历史文章:

  • QNX简介
  • QNX Neutrino微内核
  • QNX IPC机制
  • QNX进程管理器
  • QNX资源管理器
  • QNX字符I/O
  • QNX之编写资源管理器(一)
  • QNX之编写资源管理器(二)
  • QNX之编写资源管理器(三)
  • QNX之编写资源管理器(四)
  • QNX之编写资源管理器(五)
  • QNX之编写资源管理器(六)
  • QNX之编写资源管理器(七)
  • QNX之编写资源管理器(八)

Multithreaded Resource Managers

这篇文章主要描述多线程来实现资源管理器。

1. Multithreaded resource manager example

先来看个例子:

#include 
#include 
#include 
#include 
#include 

/*
 *  define THREAD_POOL_PARAM_T such that we can avoid a compiler
 *  warning when we use the dispatch_*() functions below
 */
#define THREAD_POOL_PARAM_T dispatch_context_t

#include 
#include 

static resmgr_connect_funcs_t    connect_funcs;
static resmgr_io_funcs_t         io_funcs;
static iofunc_attr_t             attr;

main(int argc, char **argv)
{
    /* declare variables we'll be using */
    thread_pool_attr_t   pool_attr;
    resmgr_attr_t        resmgr_attr;
    dispatch_t           *dpp;
    thread_pool_t        *tpp;
    dispatch_context_t   *ctp;
    int                  id;

    /* initialize dispatch interface */
    if((dpp = dispatch_create()) == NULL) {
        fprintf(stderr,
                "%s: Unable to allocate dispatch handle.\n",
                argv[0]);
        return EXIT_FAILURE;
    }

    /* initialize resource manager attributes */
    memset(&resmgr_attr, 0, sizeof resmgr_attr);
    resmgr_attr.nparts_max = 1;
    resmgr_attr.msg_max_size = 2048;

    /* initialize functions for handling messages */
    iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs, 
                     _RESMGR_IO_NFUNCS, &io_funcs);

    /* initialize attribute structure used by the device */
    iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0);

    /* attach our device name */
    id = resmgr_attach(
            dpp,            /* dispatch handle        */
            &resmgr_attr,   /* resource manager attrs */
            "/dev/sample",  /* device name            */
            _FTYPE_ANY,     /* open type              */
            0,              /* flags                  */
            &connect_funcs, /* connect routines       */
            &io_funcs,      /* I/O routines           */
            &attr);         /* handle                 */
    if(id == -1) {
        fprintf(stderr, "%s: Unable to attach name.\n", argv[0]);
        return EXIT_FAILURE;
    }

    /* initialize thread pool attributes */
    memset(&pool_attr, 0, sizeof pool_attr);
    pool_attr.handle = dpp;
    pool_attr.context_alloc = dispatch_context_alloc;
    pool_attr.block_func = dispatch_block;
    pool_attr.unblock_func = dispatch_unblock;
    pool_attr.handler_func = dispatch_handler;
    pool_attr.context_free = dispatch_context_free;
    pool_attr.lo_water = 2;
    pool_attr.hi_water = 4;
    pool_attr.increment = 1;
    pool_attr.maximum = 50;

    /* allocate a thread pool handle */
    if((tpp = thread_pool_create(&pool_attr, 
                                 POOL_FLAG_EXIT_SELF)) == NULL) {
        fprintf(stderr, "%s: Unable to initialize thread pool.\n",
                argv[0]);
        return EXIT_FAILURE;
    }

    /* start the threads, will not return */
    thread_pool_start(tpp);
}

线程池属性pool_attr控制线程池的各个方面,比如新线程启动或终止时调用哪些函数、工作线程的总数、最小数量等等。

2. Thread pool attributes

_thread_pool_attr结构如下:

typedef struct _thread_pool_attr {
  THREAD_POOL_HANDLE_T  *handle;
  THREAD_POOL_PARAM_T   *(*block_func)(THREAD_POOL_PARAM_T *ctp);
  void                  (*unblock_func)(THREAD_POOL_PARAM_T *ctp);
  int                   (*handler_func)(THREAD_POOL_PARAM_T *ctp);
  THREAD_POOL_PARAM_T   *(*context_alloc)(
                            THREAD_POOL_HANDLE_T *handle);
  void                  (*context_free)(THREAD_POOL_PARAM_T *ctp);
  pthread_attr_t        *attr;
  unsigned short        lo_water;
  unsigned short        increment;
  unsigned short        hi_water;
  unsigned short        maximum;
  unsigned              reserved[8];
} thread_pool_attr_t;

填充这个数据结构中的函数,可以是dispatch layer的函数(比如 dispatch_block()...),也可以是resmgr layer的函数(比如 resmgr_block()...),也可以是自己实现的函数。

如果不使用resmgr layer函数,则必须将THREAD_POOL_PARAM_T定义为某种上下文结构,以便库在各种函数间传递。默认情况下,它被定义为resmgr_context_t,但由于这个示例使用的dispatch layer,因此需要定义成dispatch_context_t。需要在include之前定义,因为头文件引用了THREAD_POOL_PARAM_T

上边结构告诉资源管理器如何处理多线程。在开发过程中,在设计资源管理器时应该考虑到多个线程,在测试期间,为了方便调试,可能只有一个线程在运行,在确保资源管理器基本功能稳定后,则需要尝试使用多个线程来运行调试。

  • lo_water,阻塞线程的最小数量
  • increment,每次要创建的数量,以达到lo_water
  • hi_water,阻塞线程的最大数量
  • maximum,任何时候创建线程的最大数量

maximum值应该确保始终有一个处于接收阻塞状态的线程,如果处于最大线程数,那么客户端将阻塞,直到空闲线程准备好接收数据为止。为increment指定的值将减少驱动程序需要创建线程的次数。明智的做法可能是错误的创建更多的线程,而不是一直创建/销毁它们。通过填充lo_water参数,可以随时在MsgReceive()上确定希望接收阻塞的线程数。如果接收阻塞的线程少于lo_water线程,那么increment参数指定一次应该创建多少个线程,这样至少lo_water线程的数量会再次被接收阻塞。一旦线程完成了处理,将返回到block函数。hi_water变量指定接收阻塞线程数量的上限,一旦达到这个限制,线程将自我销毁,以确保接收阻塞的线程数量不会超过hi_water。为了防止线程数量无限制的增加,maximum参数限制了同时运行线程的最大值。
当资源管理器创建线程时,可以通过thread_stack_size来指定堆栈的大小,如果想要指定堆栈的大小,优先级等,可以填充由pthread_attr_t类型指针指向的pool_attr.attr结构。

thread_pool_attr_t结构中,还包含了几个函数指针:

  • block_func(),当需要阻塞等待某些消息时调用;
  • handler_func(),当接收到消息解除阻塞后调用,在这个函数中对消息进行处理;
  • context_alloc(),新线程创建时调用,新线程使用这个上下文来工作;
  • context_free(),当线程退出时,释放这个上下文;
  • unblock_func(),当关闭线程池或改变运行线程的数量时,调用这个函数;

3. Thread pool functions

资源管理器库提供了几个线程池的函数:

  • thread_pool_create(),初始化线程池上下文,返回一个线程池的handle,用于启动线程池;
  • thread_pool_start(),启动线程池,这个函数可能返回,也可能不返回,取决于thread_pool_create()的传入flags
  • thread_pool_destroy(),销毁线程池;
  • thread_pool_control(),控制线程的数量;

你可能感兴趣的:(QNX之编写资源管理器(九))