线程池的实现设计

线程池的实现原理
线程池的概念很简单,就是new一堆线程,当有任务到来时,抓一个线程去执行,执行完之后再丢回线程池。省去了新建和注销线程的开销。
线程池工作分为以下几步:
(1)创建线程固定数目的线程(如:20个)
并让线程挂起等待任务
(2)给某个线程设置任务
(3)激活该线程,让其执行任务
(4)线程执行任务完毕后,回收该线程

虽然过程不复杂,但是实现过程中的逻辑却不简单,以darwin的源码为例:

类结构如下:(伪代码)

class ThreadTask //是一个执行任务的线程类
{
friend class ThreadPool;
public:
    Int start();       //创建线程
static void _Entry(void *inThread);   //该线程的回调函数
virtual void Entry();
Bool Active();     //激活该线程

private:
Task *m_task;

OSCond     m_Cond_Run;    //用于检测线程是否运行的条件变量
OSMutex     m_Mutex_Run;   //相对应的互斥量

OSCond     m_Cond_IsTaskRun;  //用于检测是否运行任务的条件变量
OSMutex     m_Mutex_IsTaskRun; //相对应的互斥量

};

class Task
{
friend class ThreadTask;
public:
    Bool RunTask(){ ThreadPool::RegistTask(this);}
virtual int Run()=0; //最终执行任务的函数
};

class ThreadPool
{
friend class ThreadTask;
public:
    ThreadPool(int n);   //初始化
static  void RegistTask(Task* ptask); //注册任务
private:
    List<ThreadTask*> m_useList;
    List<ThreadTask*> m_unUseList;
};

类的实现如下:(伪代码)

class MyTask :public Task
{
    int Run(){...};   //代码中,只要实现Run()函数,就可以了。
};
int main()
{
    MyTask *mytask=new MyTask();
    mytask->RunTask();   //调用RunTask()就可以是任务运行,但是一般通常把这个函数封装起来而不这样用
    return 0;
}

//取一个线程执行任务
void ThreadPool::RegistTask(Task* ptask)
{
    if(m_unUseList.empty())
    {
        //如果没有空闲的线程,那么就创建一个线程
        ThreadTask *pthread = new ThreadTask();
        pthread->start();
        m_useList.Push(pthread);
    }
    ThreadTask *pthread = m_unUseList.Pop();
    p->m_task=ptask;//给线程添加任务
    pthread->Active();//激活线程
}
//初始化n个线程,并激活
void ThreadPool::ThreadPool(int n)
{
    while(n--)
    {
        ThreadTask *pthread = new ThreadTask();
        pthread->start();
        m_useList.Push(pthread);
    }
}
//创建线程
Int ThreadTask::start()
{
    //可以看出线程的回调函数是_Entry实际上是一个静态函数,目的是为了调用各自进程的Entry()函数
    return pthread_create((pthread_t*)&m_ThreadID, &m_ThreadAttr, _Entry, (void*)this);
}
void ThreadTask::_Entry(void *inThread)
{
    //调用当前进程对应的Entry()函数
    inThread->Entry();
}
void ThreadTask::Entry()
{
    while (1)
    {
        //这一段相当于P(m_Cond_Run)
        m_Mutex_Run.Lock();
        while(!m_busy)
        {
            m_Cond_Run.Wait(&m_Mutex_Run, 500);
        }
        m_Mutex_Run.Unlock();

        //这一段相当于V(m_Cond_IsTaskRun)
        m_Mutex_IsTaskRun.Lock();
        m_IsTaskRun = TRUE;
        m_Cond_IsTaskRun.Signal();
        m_Mutex_IsTaskRun.Unlock();

        //在这里执行Run()之后再把线程放回线程池的未用队列
        if(m_Task != NULL)
        {
            m_Task->Run();
            delete m_task;
            //在这一部分还有一段用于确认是否运行完毕的PV操作,暂且省略

            //这个函数主要是把当前线程从已用队列挪到未用队列
            ThreadPool::ReclaimThread(this);
        }
        //修改状态
        m_Mutex_IsTaskRun.Lock();
        m_IsTaskRun = FALSE;
        m_Mutex_IsTaskRun.Unlock();
    }

    return NULL;
}
Bool ThreadTask::Active()
{
    m_Mutex_Run.Lock();
    if(!m_busy)
    {
        //这一段相当于V(m_Cond_Run)
        m_busy = TRUE;
        m_Cond_Run.Signal();
        m_Mutex_Run.Unlock();

        //这一段相当于P(m_Cond_IsTaskRun)
        m_Mutex_IsTaskRun.Lock();
        while(!m_IsTaskRun)
        {
            m_Cond_IsTaskRun.Wait(&m_Mutex_IsTaskRun,100);
        }
        m_Mutex_IsTaskRun.Unlock();
        return TRUE;
    }
    m_Mutex_Run.Unlock();
    return TRUE;
}
时间: 2024-10-13 11:25:29

线程池的实现设计的相关文章

线程池? 如何设计一个动态大小的线程池,有哪些方法?

[线程池?  如何设计一个动态大小的线程池,有哪些方法?] 线程池:顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中, 需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中, 从而减少创建和销毁线程对象的开销. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互.此时,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池相似,线程池在系统启动时即创建大量空闲的线程,程序将一个Runnable

线程池实现

线程池实现 Table of Contents 1 基本设计思路 2 使用线程池的优势 3 TPTask 4 TPThread 5 ThreadPool 5.1 线程管理 5.2 并发任务管理 6 实现细节 6.1 线程回调函数 6.2 线程池管理 6.2.1 线程池初始化 6.2.2 并发任务添加 6.2.3 与主线程的交互 6.2.4 线程池销毁 7 总结 1 基本设计思路 我们首先设计TPThread类,用于管理单个线程的属性和方法:有了TPThread表示的线程之后,我们定义Thread

java线程池技术

1.线程池的实现原理?简介: 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间.如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能. 线程池技术正是关注如何缩短或调整T1.T3时间的技术,从而提高服务器程序性能的.它把T1.T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理

并发编程常用工具类(二) SymaPhore实现线程池

1.symaPhore简介 symaphore(信号量)用来控制同时访问某个资源的线程数量,一般用在并发流量控制.个人对它的理解相当于是接待室每次只能接待固定数量的人,当达到最高接待数的时候,其他人就会被拦截在外等待,当前面接待完走出接待室,才会继续接待下面的人. 2.symaphore使用 symaphore有两个构造方法:构造方法Semaphore(int permits)接受一个int参数,表示可用的许可证数量,内部默认创建一个非公平锁:构造方法Semaphore(int permits,

ElasticSearch 线程池类型分析之SizeBlockingQueue

ElasticSearch 线程池类型分析之SizeBlockingQueue 尽管前面写好几篇ES线程池分析的文章(见文末参考链接),但都不太满意.但从ES的线程池中了解到了不少JAVA线程池的使用技巧,于是忍不住再写一篇(ES6.3.2版本的源码).文中给出的每个代码片断,都标明了这些代码是来自哪个类的哪个方法. ElasticSearch里面一共有四种类型的线程池,源码:ThreadPool.ThreadPoolType DIRECT("direct"), FIXED("

Linux多线程实践(9) --简单线程池的设计与实现

线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务(不止一个不同的任务)就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因.比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同

两种unix网络编程线程池的设计方法

unp27章节中的27.12中,我们的子线程是通过操作共享任务缓冲区,得到task的,也就是通过线程间共享的clifd[]数组,这个数组其实就是我们的任务数组,得到其中的connfd资源. 我们对这个任务数组的操作,需要互斥量+条件变量达到同步的目的..每个线程是无规律的从clifd得到任务,然后执行的.任务和线程之间没有对应关系.线程完成本次任务之后,如果任务数组中任然有任务,则再次运行下一个任务. 而另外的一个线程池模型中,pthread_create (&temp[i].tid, NULL

Net线程池设计

Net线程池设计 功能描述: 支持创建多个线程池,并统一管理 支持不同线程池的容量控制,以及最少活动线程的设置 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收 结构设计: ThreadWorkerPoolManager: 线程池管理器,用于统一创建,获取,销毁线程池,使用单例模式 ThreadWorkerPool: 线程池,用于管理指定数量的线程,由ThreadWorkerPoolManager管理,自身无法创建与销毁 TheadWorkerPoolItem: 线程池项,用

Nutshell.ThreadWorkerPool .Net线程池设计

功能描述: 支持创建多个线程池,并统一管理 支持不同线程池的容量控制,以及最少活动线程的设置 支持不同线程池中活动线程的闲时设置,即线程空闲时间到期后即自动被回收 结构设计: ThreadWorkerPoolManager: 线程池管理器,用于统一创建,获取,销毁线程池,使用单例模式 ThreadWorkerPool: 线程池,用于管理指定数量的线程,由ThreadWorkerPoolManager管理,自身无法创建与销毁 TheadWorkerPoolItem: 线程池项,用于包装线程工作器,