C11、线程池的使用

       线程池由四个独立的部分组成:定时器,等待,I/O,非I/O。当进程初始化时,无开销。但是,一旦有线程池函数调用,就为进程创建某些组件。

 

       多线程应用程序的困难,是面对两大问题:管理线程的创建和撤销,资源访问同步。线程池函数的功能:

一、异步调用函数:

a)         该方案是C/S应用程序的典型实现,经常处理异步I/O请求(高性能可伸缩应用程序的秘诀!)

b)        调用函数:

BOOL QueueUserWorkItem(

PTHREAD_START_ROUTINE pfnCallback, // 你的工作函数

PVOID pvContext, // 你的函数传入参数

ULONG dwFalgs); // 你不必调用CreateThread函数!不必为每个客户请求创建和撤销线程。

c)        你的工作函数原型:DWORD WINAPI YourFuncPVOID pvContext;

d)        dwFlags参数说明

n         I/OWT_EXECUTEDEFAULT

n         异步I/O: WT_EXECUTEINIOTHREAD

n         不能终止的线程:WT_EXECUTERPERSISTENTTHREAD

n         长时间运行的项目:WT_EXECUTELONGFUNCTION

e)         注意事项:避免潜在的死锁条件。

 

二、按规定的时间间隔调用函数(不必为每个基于时间的操作创建一个等待定时器对象):

a)         创建定时器队列:HANDLE CreateTimerQueue();

b)        在队列中创建定时器:

BOOL CreateTimerQueueTimer(

PHANDLE phNewTimer, // 返回的新定时器的句柄

HANDLE hTimerQueue, // 如果只创建少数几个定时器,可用NULL

WAITORTIMERCALLBACK pfnCallback, // 你的工作函数

PVOID pvContext, // 工作函数传入参数

DWORD dwDueTime,   // 经过多少ms第一次运行

DWORD dwPeriod,       // 间隔多少ms= 0,则为单步定时器(只运行一次)

ULONG dwFlags);

c)        dwFlags参数说明:

n         WT_EXECUTEINTIMERTHREAD

n         其他,见上

d)        你的工作函数原型:VOID WINAPI YourFuncPVOID pvContext, BOOL = TRUE);

e)         删除定时器(即使是单步定时器)

BOOL DeleteTimerQueueTimer(

HANDLE hTimerQueue,       // 位于哪个队列

HANDLE hTimer,                 // 要删除的定时器

HANDLE hCompletionEvent);    // 何时不再存在未处理的项目,传入INVALID_HANDLE_VALUE NULL 事件内核对象句柄。

f)         改变到期时间和间隔时间:

BOOL ChangeTimerQueueTimer(

HANDLE hTimerUeue,

HANDLE hTimer,

ULONG dwDueTime,

ULONG dwPeriod);

对单步定时器不适用。

g)        服务器终止时,只需删除此队列:

BOOL DeleteTimerQueueEx(

HANDLE hTimerQueue,

HANDLE hCompletionEvent); // 同上

 

三、当单个内核对象变为已通知状态时调用函数:

a)         调用函数:

BOOL RegisterWaitForSingleObject(

PHANDLE phNewWaitObject, // 返回的句柄,标识等待组件

HANDLE hObject,  // 标识内核对象

WATIORTIMERCALLBACK pfnCallback, // 你的工作函数

PVOID pvContext, // 传入你的工作函数的参数

ULONG dwMilliseconds, // 超时,可为0INFINITE

ULONG dwFlags);

n         负责将参数传送给线程池的等待组件,与WaitForSingleObject相似。

n         不能多次等待单个句柄,如果需要,可用DuplicateHandle复制并分开注册。

a)         你的工作函数原型:VOID WINAPI YourFunc(PVOID pvContex, BOOL); 如果等待超时了,BOOL = TRUE;如变为已通知,BOOL = FALSE

b)        dwFlags参数说明:

n         WT_EXECUTEINWAITTHREAD:运行快,有风险(无法等待其他对象得到通知)。只有当工作函数运行得很快时才使用。

n         WT_EXECUTEONLYONCE:只执行一次就停止等待该对象。

n         其他,见上

c)        取消等待组件的注册状态:

BOOL UnregisterWaitEx(

HANDLE hWaitHandle,  // 由注册函数返回的phNewWaitObject

HANDLE hCompletionEvent); // 同上

n         如无排队的工作项目,返回TRUE,否则FALSE,而GetLastError返回STATUS_PENDING

d)        注意事项:避免潜在的死锁条件。

e)         在调用UnregisterWaitEx前,不应删除内核对象句柄

 

四、当异步I/O请求完成时调用函数(常用):

a)         将一个设备与I/O组件关联的函数(I/O组件的线程全部在一个I/O组件端口上等待):

BOOL BindIoCompletionCallback(

HANDLE hDevice,

POVERLAPPED_COMPLETION_ROUTINE pfnCallback,

ULONG dwFlags); // 必须传 0.

b)        你的工作函数原型:

VOID WINAPI OverlappedCompletionRoutine(

DWORD dwErrorCode,

DWORD dwNumberOfBytesTransferred,

POVERLAPPED pOverLapped);   // OVERLAPPED结构传递给ReadFile等函数

n         关闭设备会导致他所有待处理的I/O请求立即完成,并产生错误码。所以在回调函数中应处理此情况。避免的方法是使用计数器。

以下是一个简单的C11线程池实现,包含基本的初始化、添加任务和销毁线程池的函数: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <stdatomic.h> // 最大任务数 #define MAX_TASKS 1024 // 任务结构体 typedef struct { void (*func)(void*); // 任务函数指针 void* arg; // 任务参数 } task_t; // 线程池结构体 typedef struct { pthread_t* threads; // 线程数组 atomic_int num_threads; // 线程数 atomic_int num_tasks; // 任务数 atomic_bool shutdown; // 关闭标志 pthread_mutex_t lock; // 互斥锁 pthread_cond_t task_cond; // 条件变量 task_t tasks[MAX_TASKS]; // 任务数组 } thread_pool_t; // 执行任务 static void* thread_func(void* arg) { thread_pool_t* pool = (thread_pool_t*)arg; while (1) { // 等待任务 pthread_mutex_lock(&pool->lock); while (pool->num_tasks == 0 && !pool->shutdown) { pthread_cond_wait(&pool->task_cond, &pool->lock); } // 关闭 if (pool->shutdown) { pthread_mutex_unlock(&pool->lock); pthread_exit(NULL); } // 取出任务 task_t task = pool->tasks[--pool->num_tasks]; pthread_mutex_unlock(&pool->lock); // 执行任务 task.func(task.arg); } } // 初始化线程池 int thread_pool_init(thread_pool_t* pool, int num_threads) { // 初始化互斥锁和条件变量 if (pthread_mutex_init(&pool->lock, NULL) != 0) { return -1; } if (pthread_cond_init(&pool->task_cond, NULL) != 0) { pthread_mutex_destroy(&pool->lock); return -1; } // 初始化线程数组 pool->threads = (pthread_t*)malloc(num_threads * sizeof(pthread_t)); if (pool->threads == NULL) { pthread_mutex_destroy(&pool->lock); pthread_cond_destroy(&pool->task_cond); return -1; } // 初始化变量 atomic_init(&pool->num_threads, num_threads); atomic_init(&pool->num_tasks, 0); atomic_init(&pool->shutdown, 0); // 创建线程 for (int i = 0; i < num_threads; i++) { if (pthread_create(&pool->threads[i], NULL, thread_func, pool) != 0) { thread_pool_destroy(pool); return -1; } } return 0; } // 添加任务 int thread_pool_add_task(thread_pool_t* pool, void (*func)(void*), void* arg) { if (atomic_load(&pool->shutdown)) { return -1; } // 添加任务 pthread_mutex_lock(&pool->lock); if (pool->num_tasks == MAX_TASKS) { pthread_mutex_unlock(&pool->lock); return -1; } task_t task = { func, arg }; pool->tasks[pool->num_tasks++] = task; pthread_cond_signal(&pool->task_cond); pthread_mutex_unlock(&pool->lock); return 0; } // 销毁线程池 void thread_pool_destroy(thread_pool_t* pool) { if (atomic_exchange(&pool->shutdown, 1)) { return; } // 唤醒所有等待任务的线程 pthread_mutex_lock(&pool->lock); pthread_cond_broadcast(&pool->task_cond); pthread_mutex_unlock(&pool->lock); // 等待所有线程退出 for (int i = 0; i < atomic_load(&pool->num_threads); i++) { pthread_join(pool->threads[i], NULL); } // 释放资源 free(pool->threads); pthread_mutex_destroy(&pool->lock); pthread_cond_destroy(&pool->task_cond); } ``` 使用示例: ```c void task_func(void* arg) { int* num = (int*)arg; printf("Task %d executed by thread %ld\n", *num, pthread_self()); } int main() { thread_pool_t pool; thread_pool_init(&pool, 4); int nums[10]; for (int i = 0; i < 10; i++) { nums[i] = i + 1; thread_pool_add_task(&pool, task_func, &nums[i]); } thread_pool_destroy(&pool); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值