mirror of
https://gitee.com/acl-dev/acl.git
synced 2024-12-16 01:40:52 +08:00
a3b2e1f6d1
通过给线程池中的每一个线程一个独立的线程条件变量(之前是用同一个),大大减少了线程池在任务调度时的竞争问题
243 lines
6.0 KiB
C++
243 lines
6.0 KiB
C++
#include "lib_acl.h"
|
||
#include <assert.h>
|
||
|
||
/**
|
||
* 用户自定义数据结构
|
||
*/
|
||
typedef struct THREAD_CTX {
|
||
acl_pthread_pool_t *thr_pool;
|
||
int i;
|
||
} THREAD_CTX;
|
||
|
||
/* 全局性静态变量 */
|
||
static acl_pthread_pool_t *__thr_pool = NULL;
|
||
|
||
/* 线程局部存储变量(C99支持此种方式声明,方便许多) */
|
||
static __thread unsigned int __local = 0;
|
||
|
||
static void free_buf_fn(void *arg)
|
||
{
|
||
ACL_VSTRING *buf = (ACL_VSTRING*) arg;
|
||
|
||
printf(">> current thread id=%u, buf = %s\r\n",
|
||
(unsigned int) acl_pthread_self(), acl_vstring_str(buf));
|
||
acl_vstring_free(buf);
|
||
}
|
||
|
||
static void worker_thread(void *arg)
|
||
{
|
||
THREAD_CTX *ctx = (THREAD_CTX*) arg; /* 获得用户自定义对象 */
|
||
unsigned int i = 0;
|
||
static __thread ACL_VSTRING *buf1 = NULL;
|
||
static __thread ACL_VSTRING *buf2 = NULL;
|
||
|
||
/* 仅是验证参数传递过程 */
|
||
assert(ctx->thr_pool == __thr_pool);
|
||
|
||
if (buf1 == NULL)
|
||
buf1 = acl_vstring_alloc(256);
|
||
if (buf2 == NULL)
|
||
buf2 = acl_vstring_alloc(256);
|
||
|
||
acl_vstring_sprintf(buf1, "buf1: tid=%u",
|
||
(unsigned int) acl_pthread_self());
|
||
acl_vstring_sprintf(buf2, "buf2: tid=%u",
|
||
(unsigned int) acl_pthread_self());
|
||
/* 注册函数,当该线程退出时自动释放 buf 内存空间 */
|
||
acl_pthread_atexit_add(buf1, free_buf_fn);
|
||
acl_pthread_atexit_add(buf2, free_buf_fn);
|
||
|
||
while (i < 5) {
|
||
if (__local != i)
|
||
acl_msg_fatal("__local=%d invalid", __local);
|
||
printf("thread id=%u, i=%d, __local=%d\r\n",
|
||
(unsigned int) acl_pthread_self(), ctx->i, __local);
|
||
i++;
|
||
/* 在本线程中将线程局部变量加1 */
|
||
__local++;
|
||
sleep(1);
|
||
}
|
||
|
||
acl_myfree(ctx);
|
||
|
||
/* 至此,该工作线程进入空闲状态,直到空闲超时退出 */
|
||
}
|
||
|
||
static int on_thread_init(void *arg)
|
||
{
|
||
const char *myname = "on_thread_init";
|
||
acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;
|
||
|
||
/* 判断一下,仅是为了验证参数传递过程 */
|
||
assert(thr_pool == __thr_pool);
|
||
printf("%s: thread(%u) init now\r\n", myname, (unsigned int) acl_pthread_self());
|
||
|
||
/* 返回0表示继续执行该线程获得的新任务,返回-1表示停止执行该任务 */
|
||
return (0);
|
||
}
|
||
|
||
static void on_thread_exit(void *arg)
|
||
{
|
||
const char *myname = "on_thread_exit";
|
||
acl_pthread_pool_t *thr_pool = (acl_pthread_pool_t*) arg;
|
||
|
||
/* 判断一下,仅是为了验证参数传递过程 */
|
||
assert(thr_pool == __thr_pool);
|
||
printf("%s: thread(%u) exit now\r\n", myname, (unsigned int) acl_pthread_self());
|
||
}
|
||
|
||
static void run_thread_pool(acl_pthread_pool_t *thr_pool)
|
||
{
|
||
THREAD_CTX *ctx; /* 用户自定义参数 */
|
||
|
||
/* 设置全局静态变量 */
|
||
__thr_pool = thr_pool;
|
||
|
||
/* 设置线程开始时的回调函数 */
|
||
(void) acl_pthread_pool_atinit(thr_pool, on_thread_init, thr_pool);
|
||
|
||
/* 设置线程退出时的回调函数 */
|
||
(void) acl_pthread_pool_atfree(thr_pool, on_thread_exit, thr_pool);
|
||
|
||
ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX));
|
||
assert(ctx);
|
||
ctx->thr_pool = thr_pool;
|
||
ctx->i = 0;
|
||
|
||
/**
|
||
* 向线程池中添加第一个任务,即启动第一个工作线程
|
||
* @param wq 线程池句柄
|
||
* @param worker_thread 工作线程的回调函数
|
||
* @param event_type 此处写0即可
|
||
* @param ctx 用户定义参数
|
||
*/
|
||
acl_pthread_pool_add(thr_pool, worker_thread, ctx);
|
||
sleep(1);
|
||
|
||
ctx = (THREAD_CTX*) acl_mycalloc(1, sizeof(THREAD_CTX));
|
||
assert(ctx);
|
||
ctx->thr_pool = thr_pool;
|
||
ctx->i = 1;
|
||
/* 向线程池中添加第二个任务,即启动第二个工作线程 */
|
||
acl_pthread_pool_add(thr_pool, worker_thread, ctx);
|
||
}
|
||
|
||
static void main_thread_atexit(void *arg)
|
||
{
|
||
ACL_VSTRING *buf = (ACL_VSTRING*) arg;
|
||
|
||
printf("main thread exit now, tid=%u, buf=%s\r\n",
|
||
(unsigned int) acl_pthread_self(), acl_vstring_str(buf));
|
||
printf("in the main thread_atexit, input any key to exit\r\n");
|
||
getchar();
|
||
}
|
||
|
||
static acl_pthread_pool_t *thr_pool_create(int threads, int timeout)
|
||
{
|
||
acl_pthread_pool_attr_t attr;
|
||
acl_pthread_pool_t *thr_pool;
|
||
|
||
acl_pthread_pool_attr_init(&attr);
|
||
acl_pthread_pool_attr_set_threads_limit(&attr, threads);
|
||
acl_pthread_pool_attr_set_idle_timeout(&attr, timeout);
|
||
|
||
/* 创建半驻留线程句柄 */
|
||
thr_pool = acl_pthread_pool_create(&attr);
|
||
assert(thr_pool);
|
||
return (thr_pool);
|
||
}
|
||
|
||
typedef struct {
|
||
ACL_VSTREAM *fp;
|
||
int i;
|
||
} RUN_CTX;
|
||
static acl_pthread_mutex_t __mutex;
|
||
static int __i = 0;
|
||
static void run_thread(void *arg)
|
||
{
|
||
RUN_CTX *ctx = (RUN_CTX*) arg;
|
||
|
||
acl_pthread_mutex_lock(&__mutex);
|
||
if (0)
|
||
acl_vstream_fprintf(ctx->fp, "hello world, id: %d, i: %d\n", ctx->i, __i++);
|
||
else
|
||
__i++;
|
||
acl_pthread_mutex_unlock(&__mutex);
|
||
acl_myfree(ctx);
|
||
}
|
||
|
||
static void test_thread_pool(void)
|
||
{
|
||
acl_pthread_pool_t *thr_pool;
|
||
ACL_VSTREAM *fp = acl_vstream_fopen("test.log", O_WRONLY | O_CREAT, 0600, 4096);
|
||
int i;
|
||
|
||
acl_pthread_mutex_init(&__mutex, NULL);
|
||
thr_pool = acl_thread_pool_create(100, 10);
|
||
|
||
for (i = 0; i < 1000000; i++) {
|
||
RUN_CTX *ctx = (RUN_CTX*) acl_mymalloc(sizeof(RUN_CTX));
|
||
ctx->fp = fp;
|
||
ctx->i = i;
|
||
acl_pthread_pool_add(thr_pool, run_thread, ctx);
|
||
}
|
||
|
||
acl_pthread_pool_destroy(thr_pool);
|
||
acl_pthread_mutex_destroy(&__mutex);
|
||
acl_vstream_close(fp);
|
||
printf("last i: %d\r\n", __i);
|
||
}
|
||
|
||
int main(int argc acl_unused, char *argv[] acl_unused)
|
||
{
|
||
acl_pthread_pool_t *thr_pool;
|
||
int max_threads = 20; /* 最多并发20个线程 */
|
||
int idle_timeout = 10; /* 每个工作线程空闲10秒后自动退出 */
|
||
static __thread ACL_VSTRING *buf = NULL;
|
||
|
||
if (1) {
|
||
test_thread_pool();
|
||
exit (0);
|
||
}
|
||
|
||
buf = acl_vstring_alloc(256);
|
||
acl_vstring_sprintf(buf, "in main thread, id=%u",
|
||
(unsigned int) acl_pthread_self());
|
||
acl_pthread_atexit_add(buf, main_thread_atexit);
|
||
|
||
|
||
thr_pool = thr_pool_create(max_threads, idle_timeout);
|
||
run_thread_pool(thr_pool);
|
||
|
||
if (0) {
|
||
/* 如果立即运行 acl_pthread_pool_destroy,则由于调用了线程池销毁函数,
|
||
* 主线程便立刻通知空闲线程退出,所有空闲线程不必等待空闲超时时间便可退出,
|
||
*/
|
||
printf("> wait all threads to be idle and free thread pool\r\n");
|
||
/* 立即销毁线程池 */
|
||
acl_pthread_pool_destroy(thr_pool);
|
||
} else {
|
||
/* 因为不立即调用 acl_pthread_pool_destroy,所有所有空闲线程都是当空闲
|
||
* 超时时间到达后才退出
|
||
*/
|
||
while (1) {
|
||
int ret;
|
||
|
||
ret = acl_pthread_pool_size(thr_pool);
|
||
if (ret == 0)
|
||
break;
|
||
printf("> current threads in thread pool is: %d\r\n", ret);
|
||
sleep(1);
|
||
}
|
||
/* 线程池中的工作线程数为0时销毁线程池 */
|
||
printf("> all worker thread exit now\r\n");
|
||
acl_pthread_pool_destroy(thr_pool);
|
||
}
|
||
|
||
/* 主线程等待用户在终端输入任意字符后退出 */
|
||
printf("> enter any key to exit\r\n");
|
||
getchar();
|
||
|
||
return (0);
|
||
}
|