由于工作需要实现一个线程池,所以这里做一个小总结并分享给大家,如有问题请大家不吝指教。
- 线程池(thread pool)是线程的一种使用模式。因为,过多的线程调度开销会影响缓存局部性和系统整体性能。所以,通过线程池维护着多个线程,等待着监督管理者分配可并发执行的任务,这就避免了在处理短时间任务时创建与销毁线程的代价。 线程池不仅能够保证内核的充分利用,还能防止过分调度。
- 可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。
完整代码下载地址:线程池代码下载链接
thrpool.c文件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include "thrPool.h"
static void *thread_start(struct thrPool *pool) {
for (;;) {
printf("Wait cond Current thread id: %d\n", (unsigned int)pthread_self());
pthread_mutex_lock(&pool->mutex);
while (pool->jobSize == 0 && !pool->destroyFlag) {
pthread_cond_wait(&pool->cond, &pool->mutex);
//printf("get new job: thread id: %d\n", (unsigned int)pthread_self());
}
if (pool->destroyFlag) {
pthread_mutex_unlock(&pool->mutex);
//printf("thread %d will exit.\n", (unsigned int )pthread_self());
pthread_exit(NULL);
}
// 获取任务并执行
}
// never executed
pthread_exit(NULL);
return NULL;
}
int thrPoolInit(struct thrPool **pool, unsigned int number)
{
int val = -1;
if ((number < 1) && (number > THR_MAX_NUM) && (pool == NULL)) {
printf("Invalid Params.\n");
val = RET_INVALID_PARAMS;
goto _err_out_params;
}
struct thrPool *tmp = malloc(sizeof(struct thrPool));
if (tmp == NULL) {
printf("Alloc Mem Fail.\n");
val = RET_NO_MEMORY;
goto _err_out_pool_mem;
}
val = pthread_mutex_init(&tmp->mutex, NULL);
if (val < 0) {
printf("Mutex Init Fail.\n");
val = RET_ERROR;
goto _err_out_mutex_init;
}
val = pthread_cond_init(&tmp->cond, NULL);
if (val < 0) {
printf("Cond Init Fail.\n");
val = RET_ERROR;
goto _err_out_cond_init;
}
val = thrJobInit(&tmp->jobRoot);
if (val < 0) {
printf("Init Job List Fail.\n");
val = RET_ERROR;
goto _err_out_job_init;
}
int i = 0;
for (i = 0; i < number; i++) {
val = pthread_create(&tmp->threadId[i], NULL, (void *)&thread_start, tmp);
if (val != 0) {
printf("Create Thread Fail.\n");
val = RET_ERROR;
goto _err_out_thread_create;
}
}
if (i != number) {
goto _err_out_thread_create2;
}
tmp->destroyFlag = 0;
tmp->thrNum = number;
*pool = tmp;
return RET_OK;
_err_out_thread_create2:
// wakeup all thread
pthread_cond_broadcast(&tmp->cond);
for (int k = 0; k < number; k++) {
if (tmp->threadId[k] != 0)
pthread_join(tmp->threadId[k], NULL); //block
};
_err_out_thread_create:
thrJobDestroy(tmp->jobRoot);
_err_out_job_init:
pthread_cond_destroy(&tmp->cond);
_err_out_cond_init:
pthread_mutex_destroy(&tmp->mutex);
_err_out_mutex_init:
free(tmp);
_err_out_pool_mem:
_err_out_params:
return val;
}
int thrPoolWorkerAdd(struct thrPool *pool, subThrFunc func, void *args)
{
int val = -1;
if ((pool == NULL) && (func == NULL) && (args == NULL)) {
return RET_INVALID_PARAMS;
}
struct thrJobNode *newJobNode = (struct thrJobNode *)malloc(sizeof( struct thrJobNode ));
if (newJobNode == NULL) {
printf("Alloc Mem Fail.\n");
val = RET_NO_MEMORY;
goto _err_out_new_job;
}
newJobNode->procFunction = func;
newJobNode->args = args;
newJobNode->next = NULL;
// add new job to list(tail);
pthread_mutex_lock(&pool->mutex);
struct thrJobNode *node = pool->jobRoot;
assert(node != NULL);
while(node->next != NULL) {
node = node->next;
}
node->next = newJobNode;
pool->jobSize++;
pthread_mutex_unlock(&pool->mutex);
// wakeup one thread, if all thread busy,
pthread_cond_signal(&pool->cond);
//printf("Add New Job Ok.\n");
return RET_OK;
_err_out_new_job:
return val;
}
int thrPoolExit(struct thrPool *pool)
{
int val = -1;
if (pool == NULL) {
printf("Invalid Params.\n");
val = RET_INVALID_PARAMS;
goto _err_out_params;
}
if (pool->destroyFlag) {
return RET_OK;
}
printf("size:%d\n", pool->jobSize);
pool->destroyFlag = 1;
pthread_cond_broadcast(&pool->cond);
for (int i = 0; i < pool->thrNum; i++) {
val = pthread_join(pool->threadId[i], NULL);
}
printf("Join Thraed ok.\n");
struct thrJobNode *head = pool->jobRoot;
assert(head != NULL);
while (head->next != NULL) {
struct thrJobNode *tmp = head->next;
head->next = tmp->next;
tmp->next = NULL;
free(tmp);
tmp = NULL;
}
thrJobDestroy(pool->jobRoot);
pthread_mutex_destroy(&pool->mutex);
pthread_cond_destroy(&pool->cond);
free(pool);
pool = NULL;
return RET_OK;
_err_out_params:
return val;
}
测试用例main.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "thrPool.h"
struct testDataInfo {
int a;
};
static void testFunc(void *args)
{
struct testDataInfo *data = (struct testDataInfo *)args;
//sleep(data->a);
printf("\n=====================\nthread id:%d data: %d\n", (unsigned int)pthread_self(), data->a);
return;
}
int main (void)
{
int val = -1;
int thrNum = 5;
struct thrPool *pool = NULL;
struct testDataInfo *data = malloc(sizeof( struct testDataInfo ));
struct testDataInfo *data1 = malloc(sizeof( struct testDataInfo ));
struct testDataInfo *data2 = malloc(sizeof( struct testDataInfo ));
val = thrPoolInit(&pool, thrNum);
if (val != 0) {
printf("Init Pool Fail.\n");
goto _err_out_init;
}
while(1) {
data->a = 3;
thrPoolWorkerAdd(pool, (void *)&testFunc, data);
data1->a = 1;
thrPoolWorkerAdd(pool, (void *)&testFunc, data1);
data2->a = 5;
thrPoolWorkerAdd(pool, (void *)&testFunc, data2);
sleep(2);
}
val = thrPoolExit(pool);
while(1) {
sleep(100);
}
return 0;
_err_out_init:
exit(1);
}
测试结果:
./a.out
Wait cond Current thread id: -662223104
Wait cond Current thread id: -679008512
Wait cond Current thread id: -670615808
Wait cond Current thread id: -805308672
Wait cond Current thread id: -687401216
=====================
thread id:-662223104 data: 3
Wait cond Current thread id: -662223104
=====================
thread id:-670615808 data: 1
Wait cond Current thread id: -670615808
=====================
thread id:-679008512 data: 5
Wait cond Current thread id: -679008512
=====================
thread id:-805308672 data: 3