美文网首页QNX操作系统
QNX之编写资源管理器(九)

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

作者: Loyen | 来源:发表于2019-01-11 23:01 被阅读0次

    QNX相关历史文章:

    Multithreaded Resource Managers

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

    1. Multithreaded resource manager example

    先来看个例子:

    #include <errno.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    /*
     *  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 <sys/iofunc.h>
    #include <sys/dispatch.h>
    
    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之编写资源管理器(九)

        本文链接:https://www.haomeiwen.com/subject/hdifdqtx.html