诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP 或 POP)、通过 JMS 队列或者可能通过轮询数据库。不管请求如何到达,服务器应用程序中经常出现的情况是:单个任务处理的时间很短而请求的数目却是巨大的。
线程池技术是一种“资源池化”技术,这种技术的思想是利用已有的线程来服务需要处理的任务。
哪种情况下使用线程池技术?服务器处理的任务数量大,并且单个任务的处理时间比较短,这种情况下适合使用线程池技术。因为如果不采用线程池技术,那么服务器就需要为每个短小的任务创建线程,并在任务完成之后销毁线程。大量频繁地创建/销毁线程将耗费很多系统资源,从而降低服务器性能。
一般一个简单线程池至少包含下列组成部分。
(1) 线程池管理器(ThreadPoolManager):用于创建并管理线程池
(2)工作线程(WorkThread): 线程池中线程
(3)任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
(4)任务队列:用于存放没有处理的任务。提供一种缓冲机制。
一个线程池的例子(代码来源:https://github.com/Pithikos/C-Thread-Pool)
/* Binary semaphore */
typedef struct bsem {
pthread_mutex_t mutex;//互斥变量
pthread_cond_t cond;//条件变量
int v; //v的值只有0,1两种
} bsem;
/* Job */ /* 任务接口 */
typedef struct job{
struct job* prev; /* pointer to previous job */
void (*function)(void* arg); /* function pointer */ /* 指向任务需要执行的函数 */
void* arg; /* function's argument */ /* 上述函数的参数。如果需要传递多个参数,那么arg应该是结构体指针 */
} job;
/* Job queue */ /* 任务队列 */
typedef struct jobqueue{
pthread_mutex_t rwmutex; /* used for queue r/w access */ /* 同步队列的读写操作,避免同时操作读和写 */
job *front; /* pointer to front of queue */
job *rear; /* pointer to rear of queue */
bsem *has_jobs; /* flag as binary semaphore */
int len; /* number of jobs in queue */
} jobqueue;
/* Thread */ /* 工作线程 */
typedef struct thread{
int id; /* friendly id */ /* 标识第几个线程 */
pthread_t pthread; /* pointer to actual thread */ /* 真正的线程ID */
struct thpool_* thpool_p; /* access to thpool */ /* 指向该线程所在的线程池 */
} thread;
/* Threadpool */ /* 线程池管理器 */
typedef struct thpool_{
thread** threads; /* pointer to threads */ /* 指向存放线程的数组 */
volatile int num_threads_alive; /* threads currently alive */ /* 线程池中线程总数 */
volatile int num_threads_working; /* threads currently working */ /* 当前正在工作的线程数目 */
pthread_mutex_t thcount_lock; /* used for thread count etc */ /* 线程池操作的互斥锁 */
pthread_cond_t threads_all_idle; /* signal to thpool_wait */ /* 等待所有任务均完成的条件变量 */
jobqueue jobqueue; /* job queue */ /* 指向任务队列 */
} thpool_;