本文转至:http://hi.baidu.com/lifepath/blog/item/0eb8ea5d6321c244fbf2c0d0.html
什么时候需要创建线程池呢?简单的说,如果一个应用需要频繁的创建和销毁线程,而任务执行的时间又非常短,这样线程创建和销毁的带来的开销就不容忽视,这时也是线程池该出场的机会了。如果线程创建和销毁时间相比任务执行时间可以忽略不计,则没有必要使用线程池了。
下面是Linux系统下用C语言创建的一个线程池。线程池会维护一个任务链表(每个CThread_worker结构就是一个任务)。
pool_init()函数预先创建好max_thread_num个线程,每个线程执thread_routine ()函数。该函数中
- while (pool->cur_queue_size == 0)
- {
- pthread_cond_wait (&(pool->queue_ready),&(pool->queue_lock));
- }
表示如果任务链表中没有任务,则该线程出于阻塞等待状态。否则从队列中取出任务并执行。
pool_add_worker()函数向线程池的任务链表中加入一个任务,加入后通过调用pthread_cond_signal (&(pool->queue_ready))唤醒一个出于阻塞状态的线程(如果有的话)。
pool_destroy ()函数用于销毁线程池,线程池任务链表中的任务不会再被执行,但是正在运行的线程会一直把任务运行完后再退出。
下面贴出完整代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
/*
*线程池里所有运行和等待的任务都是一个CThread_worker
*由于所有任务都在链表里,所以是一个链表结构
*/
typedef struct worker
{
/*回调函数,任务运行时会调用此函数,注意也可声明成其它形式*/
void *(*process) (void *arg);
void *arg;/*回调函数的参数*/
struct worker *next;
} CThread_worker;
/*线程池结构*/
typedef struct
{
pthread_mutex_t queue_lock;
pthread_cond_t queue_ready;
/*链表结构,线程池中所有等待任务*/
CThread_worker *queue_head;
/*是否销毁线程池*/
int shutdown;
pthread_t *threadid;
/*线程池中允许的活动线程数目*/
int max_thread_num;
/*当前等待队列的任务数目*/
int cur_queue_size;
} CThread_pool;
int pool_add_worker (void *(*process) (void *arg), void *arg);
void *thread_routine (void *arg);
static CThread_pool *pool = NULL;
void
pool_init (int max_thread_num)
{
pool = (CThread_pool *) malloc (sizeof (CThread_pool));
pthread_mutex_init (&(pool->queue_lock), NULL);
pthread_cond_init (&(pool->queue_ready), NULL);
pool->queue_head = NULL;
pool->max_thread_num = max_thread_num;
pool->cur_queue_size = 0;
pool->shutdown = 0;
pool->threadid =
(pthread_t *) malloc (max_thread_num * sizeof (pthread_t));
int i = 0;
for (i = 0; i < max_thread_num; i++)
{
pthread_create (&(pool->threadid[i]), NULL, thread_routine,
NULL);
}
}
/*向线程池中加入任务*/
int
pool_add_worker (void *(*process) (void *arg), void *arg)
{
/*构造一个新任务*/
CThread_worker *newworker =
(CThread_worker *) malloc (sizeof (CThread_worker));
newworker->process = process;
newworker->arg = arg;
newworker->next = NULL;/*别忘置空*/
pthread_mutex_lock (&(pool->queue_lock));
/*将任务加入到等待队列中*/
CThread_worker *member = pool->queue_head;
if (member != NULL)
{
while (member->next != NULL)
member = member->next;
member->next = newworker;
}
else
{
pool->queue_head = newworker;
}
assert (pool->queue_head != NULL);
pool->cur_queue_size++;
pthread_mutex_unlock (&(pool->queue_lock));
/*好了,等待队列中有任务了,唤醒一个等待线程;
注意如果所有线程都在忙碌,这句没有任何作用*/
pthread_cond_signal (&(pool->queue_ready));
return 0;
}
/*销毁线程池,等待队列中的任务不会再被执行,但是正在运行的线程会一直
把任务运行完后再退出*/
int
pool_destroy ()
{
if (pool->shutdown)
return -1;/*防止两次调用*/
pool->shutdown = 1;
/*唤醒所有等待线程,线程池要销毁了*/
pthread_cond_broadcast (&(pool->queue_ready));
/*阻塞等待线程退出,否则就成僵尸了*/
int i;
for (i = 0; i < pool->max_thread_num; i++)
pthread_join (pool->threadid[i], NULL);
free (pool->threadid);
/*销毁等待队列*/
CThread_worker *head = NULL;
while (pool->queue_head != NULL)
{
head = pool->queue_head;
pool->queue_head = pool->queue_head->next;
free (head);
}
/*条件变量和互斥量也别忘了销毁*/
pthread_mutex_destroy(&(pool->queue_lock));
pthread_cond_destroy(&(pool->queue_ready));
free (pool);
/*销毁后指针置空是个好习惯*/
pool=NULL;
return 0;
}
void *
thread_routine (void *arg)
{
printf ("starting thread 0x%x\n", pthread_self ());
while (1)
{
pthread_mutex_lock (&(pool->queue_lock));
/*如果等待队列为0并且不销毁线程池,则处于阻塞状态; 注意
pthread_cond_wait是一个原子操作,等待前会解锁,唤醒后会加锁*/
while (pool->cur_queue_size == 0 && !pool->shutdown)
{
printf ("thread 0x%x is waiting\n", pthread_self ());
pthread_cond_wait (&(pool->queue_ready), &(pool->queue_lock));
}
/*线程池要销毁了*/
if (pool->shutdown)
{
/*遇到break,continue,return等跳转语句,千万不要忘记先解锁*/
pthread_mutex_unlock (&(pool->queue_lock));
printf ("thread 0x%x will exit\n", pthread_self ());
pthread_exit (NULL);
}
printf ("thread 0x%x is starting to work\n", pthread_self ());
/*assert是调试的好帮手*/
assert (pool->cur_queue_size != 0);
assert (pool->queue_head != NULL);
/*等待队列长度减去1,并取出链表中的头元素*/
pool->cur_queue_size--;
CThread_worker *worker = pool->queue_head;
pool->queue_head = worker->next;
pthread_mutex_unlock (&(pool->queue_lock));
/*调用回调函数,执行任务*/
(*(worker->process)) (worker->arg);
free (worker);
worker = NULL;
}
/*这一句应该是不可达的*/
pthread_exit (NULL);
}
下面是测试代码
void *
myprocess (void *arg)
{
printf ("threadid is 0x%x, working on task %d\n", pthread_self (),*(int *) arg);
sleep (1);/*休息一秒,延长任务的执行时间*/
return NULL;
}
int
main (int argc, char **argv)
{
pool_init (3);/*线程池中最多三个活动线程*/
/*连续向池中投入10个任务*/
int *workingnum = (int *) malloc (sizeof (int) * 10);
int i;
for (i = 0; i < 10; i++)
{
workingnum[i] = i;
pool_add_worker (myprocess, &workingnum[i]);
}
/*等待所有任务完成*/
sleep (5);
/*销毁线程池*/
pool_destroy ();
free (workingnum);
return 0;
}
将上述所有代码放入threadpool.c文件中,
在Linux输入编译命令
$ gcc -o threadpool threadpool.c -lpthread
以下是运行结果
starting thread 0xb7df6b90
thread 0xb7df6b90 is waiting
starting thread 0xb75f5b90
thread 0xb75f5b90 is waiting
starting thread 0xb6df4b90
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 0
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 1
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 2
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 3
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 4
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 5
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 6
thread 0xb75f5b90 is starting to work
threadid is 0xb75f5b90, working on task 7
thread 0xb6df4b90 is starting to work
threadid is 0xb6df4b90, working on task 8
thread 0xb7df6b90 is starting to work
threadid is 0xb7df6b90, working on task 9
thread 0xb75f5b90 is waiting
thread 0xb6df4b90 is waiting
thread 0xb7df6b90 is waiting
thread 0xb75f5b90 will exit
thread 0xb6df4b90 will exit
thread 0xb7df6b90 will exit
分享到:
相关推荐
在Linux下用C写的一个简易线程池。系统是RedHat 9,gcc版本"gcc version 4.1.2 20071124 (Red Hat 4.1.2-42)"。文件夹里的源码是按工程组织好的,在文件夹下的test目录下面有一个小的测试程序和Makefile,编译后即可...
本项目提供了一个关于“Linux C语言线程池、状态机和并发处理”的Demo,非常适合初学者理解和实践多线程技术。下面将详细阐述这些知识点。 首先,线程池是一种线程管理机制,它预先创建了一组线程,待有任务需要...
### Linux 下 C 语言线程池实现解析 #### 一、引言 在现代软件开发中,线程池技术被广泛应用于并发编程场景,尤其是在服务器端应用中,它能够显著提高程序性能,减少资源消耗。本文将深入探讨 Linux 系统下基于 C ...
linux系统下C语言 利用线程池技术实现CP命令 压缩包包含:源代码+开发说明PPT 线程池头文件: //任务 struct task { void *(*task)(void *arg); void *arg; struct task *next; }; //线程池 typedef struct ...
下面是 Linux 系统下用 C 语言创建的一个线程池。线程池会维护一个任务链表(每个 CThread_worker 结构就是一个任务)。pool_init() 函数预先创建好 max_thread_num 个线程,每个线程执行 thread_routine() 函数。该...
以上就是关于“Linux线程池,C语言实现”的主要技术要点。实际的代码实现会涉及到这些概念的具体应用和细节处理。在开发过程中,要充分考虑线程池的扩展性、可靠性和效率,以满足不同应用场景的需求。
下面是一个简单的线程池实现步骤: 1. **初始化线程池**:设置线程池大小,创建相应数量的工作线程,并初始化任务队列。 2. **创建任务**:定义任务结构体,包含任务函数和参数。 3. **提交任务**:将任务放入任务...
总的来说,这个项目提供了一个基础的C语言线程池实现,展示了如何利用POSIX线程在Linux环境下进行多线程编程。理解和实现这样的线程池不仅可以提高程序的效率,还能帮助开发者深入理解操作系统级的并发编程。
是操作系统中的一种资源管理机制,它预先创建一组线程,这些线程在初始状态下处于等待状态,当有新任务需要处理时,线程池会从已创建的线程中挑选一个空闲线程去执行任务,完成任务后线程返回到线程池,等待下一次...
因此,针对C语言环境下的线程池实现变得尤为重要。 ##### 4.1 关键数据结构 - `tp_work_desc`: 描述了线程执行任务时所需的一些信息,具体内容取决于具体应用场景,需由用户自定义。 - `tp_work`: 定义了线程将要...
在Linux系统下,C语言是实现底层编程和高性能服务器应用的常见选择。本文将深入探讨如何利用C语言、Epoll事件模型、线程池以及数据库连接池来构建一个高并发的MySQL连接服务。 1. **C语言与MySQL连接**: C语言...
本实例将深入探讨如何在Linux下实现一个简单的线程池,并介绍相关的关键知识点。 1. **线程与线程池的概念** - **线程**:是操作系统分配CPU时间片的基本单位,是程序执行的流,一个进程中可以包含多个线程,它们...
在Linux系统编程中,C语言线程池的实现是一个高级话题,它涉及到多线程、进程间通信(IPC)和任务调度等复杂概念。本文将深入探讨如何利用线程池来实现一个类似于`cp`命令的功能,即高效地进行文件复制。 首先,...
通过提供的代码示例,可以看出线程池的基本组成部分和工作流程,这对于理解和实现一个通用线程池具有重要的参考价值。在实际应用中,可以根据具体的业务场景和性能需求,进一步优化线程池的设计,以达到最佳的效果。
总结来说,"linux下c++线程池"这个资源提供了一个简单的线程池实现,可以帮助开发者了解如何在Linux环境中利用C++11的线程库创建和管理线程池。通过分析和学习这个示例,你可以掌握线程池的基本原理和实践技巧,为你...
简单的linux多线程实现,含互斥锁的使用
本项目提供了一个C语言实现的线程池函数,包含了多个源代码文件和Source Insight工程文件,便于开发者进行学习和调试。 首先,我们需要理解线程的概念。线程是操作系统分配CPU时间的基本单位,相比于进程,线程共享...
- `CThread`是所有线程类的基类,同样定义了一个`Run`方法,该方法由子类实现具体的执行逻辑。 - `CWorkerThread`是实际执行任务的线程类,继承自`CThread`。 ##### 3. **线程池类** - `CThreadPool`负责管理...
在Linux环境下,通过C语言实现线程池是一种常见的编程实践。 在给定的资源中,"200行C代码实现简单线程池.doc"可能包含了详细的设计和实现步骤,以及如何在实际项目中应用线程池的文档。而"threadpool.c"则是实际的...
在Linux环境下,使用C语言实现线程池具有一定的挑战性,但同时也提供了极高的灵活性和性能控制。C语言的底层操作能力和对内存的直接访问使得开发者能够更精细地控制线程的创建、调度和销毁过程。然而,这也意味着...