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()
,控制线程的数量;