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

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(),控制线程的数量;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容

  • 一 昨天约上好友走路,勤快的她,已经在体育中心太极馆开练好几天了。说到要上班了,她莫名苦恼,晚上开始睡不着觉了。 ...
    丁若木阅读 456评论 2 12
  • 顿感,是这样一种神奇的特性,不会因为别人责骂而内心愧疚或者煎熬,不会因为她人赞美,而心欢呼雀跃,带我撑过一些很难熬...
    击空留影阅读 656评论 0 0