线程池是由服务器预先创建的一组子线程,线程池中的线程数量应该和 CPU 数量差不多。线程池中的所 有子线程都运行着相同的代码。当有新的任务到来时,主线程将通过某种方式选择线程池中的某一个子 线程来为之服务。相比与动态的创建子线程,选择一个已经存在的子线程的代价显然要小得多。
主线程和所有子线程通过一个共享的工作队列来同步,子线程都睡眠在该工作队列上。当有新的任 务到来时,主线程将任务添加到工作队列中。这将唤醒正在等待任务的子线程,不过只有一个子线 程将获得新任务的”接管权“,它可以从工作队列中取出任务并执行之,而其他子线程将继续睡眠在 工作队列上。
在RTSP项目中的线程池代码理解:
实现ThreadPool线程池类:
成员变量:
std::queue<Task> mTaskQueue;
std::mutex mMtx; // 互斥锁.
std::condition_variable mCon; // 条件变量.
std::vector<MThread> mThreads;
bool mQuit;
成员函数:
static ThreadPool* createNew(int num);
explicit ThreadPool(int num);
~ThreadPool();
void addTask(Task& task);
在服务器启动的时候就要新建好线程组,所以在ThreadPool构造函数的时候就需要createThreads
void ThreadPool::createThreads()
{
std::unique_lock <std::mutex> lck(mMtx);
for(auto & mThread : mThreads)
mThread.start(this);
}
创建好线程组后每个线程都会循环等待任务的到来,一旦任务队列中有任务来的时候就会弹出并进行处理。
void ThreadPool::loop(){
while(!mQuit){
std::unique_lock <std::mutex> lck(mMtx);
if (mTaskQueue.empty()) {
mCon.wait(lck);
}
if(mTaskQueue.empty())
continue;
Task task = mTaskQueue.front();
mTaskQueue.pop();
task.handle();
}
}
最后就是如何往任务队列中添加任务:
void ThreadPool::addTask(ThreadPool::Task& task)
{
std::unique_lock <std::mutex> lck(mMtx);
mTaskQueue.push(task);
mCon.notify_one();
}
在RTSP服务器中添加任务就是读取本地的aac和h264文件。
在H264FileMediaSource.cpp文件中,在构造函数时向线程池中添加任务。
在AACFileMediaSource.cpp文件中,在构造函数时向线程池中添加任务。
然后在loop中就会弹出任务并进行对应的处理。