SyncQueue.h:
半同步半异步队列
#pragma once
#include <list>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <iostream>
using namespace std;
template<typename T>
class SyncQueue
{
public:
SyncQueue(int maxSize) :m_maxSize(maxSize), m_needStop(false)
{
}
void Put(const T&x)
{
Add(x);
}
void Put(T&& x)
{
Add(forward<T>(x));
}
void Take(list<T>& list)
{
/*
1.先创建一个unique_lock获取mutex
2.通过条件变量m_notEmpty来等待判断式(一个是停止的标志,另一个是不为空的条件)
当不满足任何一个条件时,条件变量会释放mutex并将线程置于waiting状态,等待其它线程调用
notify_one/notify_all将其唤醒;
当满足任一条件时,则继续往下执行后面的逻辑,即将队列中的任务取出,并唤醒一个正处于等待状态的添加
任务的线程去添加任务。
3.当处于waiting状态的线程被notify_one或notify_all唤醒时,条件变量会先重新获取mutex,然后再检查条件是否
满足,如果满足,则往下执行,如果不满足,则释放mutex继续等待
*/
unique_lock<mutex> locker(m_mutex);
m_notEmpty.wait(locker, [this] {return m_needStop || NotEmpty(); });
if (m_needStop)
return;
list = move(m_queue);
m_notFull.notify_one();
}
void Take(T& t)
{
unique_lock<mutex> locker(m_mutex);
m_notEmpty.wait(locker, [this] {return m_needStop || NotEmpty(); });
if (m_needStop)
return;
t = m_queue.front();
m_queue.pop_front();
m_notFull.notify_one();
}
void Stop()
{
{
lock_guard<mutex> locker(m_mutex);
m_needStop = true;
}
m_notFull.notify_all();
m_notEmpty.notify_all();
}
bool Empty()
{
lock_guard<mutex> locker(m_mutex);
return m_queue.empty();
}
bool Full()
{
lock_guard<mutex> locker(m_mutex);
return m_queue.size() == m_maxSize;
}
size_t Size()
{
lock_guard<mutex> locker(m_mutex);
return m_queue.size();
}
int Count()
{
return m_queue.size();
}
private:
bool NotFull()const
{
bool full = m_queue.size() >= m_maxSize;
if (full)
cout << "缓冲区满了,需要等待..." << endl;
return !full;
}
bool NotEmpty()const
{
bool empty = m_queue.empty();
if (empty)
cout << "缓冲区空了,需要等待...,异步层的线程ID:" << this_thread::get_id() << endl;
return !empty;
}
template<typename F>
void Add(F&& x)
{
unique_lock<mutex> locker(m_mutex);
m_notFull.wait(locker, [this] {return m_needStop || NotFull(); });
if (m_needStop)
return;
m_queue.push_back(forward<F>(x));
m_notEmpty.notify_one();
}
private:
list<T> m_queue; //缓冲区
mutex m_mutex; //互斥量和条件变量结合超来使用
condition_variable m_notEmpty; //不为空的条件变量
condition_variable m_notFull; //没有满的条件变量
int m_maxSize; //同步队列最大的size
bool m_needStop; // 停止的标志
};
ThreadPool.h:线程池
#pragma once
#include <list>
#include <thread>
#include <functional>
#include <memory>
#include <atomic>
#include "SyncQueue.h"
using namespace std;
const int MaxTaskCount = 100;
class ThreadPool
{
public:
using Task = function<void()>;
ThreadPool(int numThreads = thread::hardware_concurrency()) :m_queue(MaxTaskCount)
{
Start(numThreads);
}
~ThreadPool()
{
// 如果没有停止时则主动停止线程池
Stop();
}
void Stop()
{
// 保证多线程情况下只调用一次StopThreadGroup
call_once(m_flag, [this] {StopThreadGroup(); });
}
void AddTask(Task&& task)
{
m_queue.Put(forward<Task>(task));
}
void AddTask(const Task& task)
{
m_queue.Put(task);
}
private:
void Start(int numThreads)
{
m_running = true;
// 创建线程组
for (int i =0;i<numThreads;++i)
{
m_threadgroup.push_back(make_shared<thread>(&ThreadPool::RunInThread, this));
}
}
void RunInThread()
{
while (m_running)
{
// 取任务分别执行
list<Task> list;
m_queue.Take(list);
for (auto& task:list)
{
if (!m_running)
return;
task();
}
}
}
void StopThreadGroup()
{
m_queue.Stop(); //让同步队列中的线程停止
m_running = false; //置为false,让内部线程跳出循环并退出
for (auto thread:m_threadgroup) //等待线程结束
{
if (thread)
{
thread->join();
}
}
m_threadgroup.clear();
}
private:
list<shared_ptr<thread>> m_threadgroup; //处理任务的线程组
SyncQueue<Task> m_queue; //同步队列
atomic_bool m_running; // 是否停止的标志
once_flag m_flag;
};
测试代码:
// ThreadPool.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include "ThreadPool.h"
#include <thread>
using namespace std;
int main()
{
ThreadPool pool{2};
thread thd1([&pool] {
for (int i = 0;i<10;i++)
{
auto thdId = this_thread::get_id();
pool.AddTask([thdId]
{
cout << "同步线程1的线程ID: " << thdId << endl;
});
}
});
thread thd2([&pool] {
for (int i = 0;i<10;i++)
{
auto thdId = this_thread::get_id();
pool.AddTask([thdId] {
cout << "同步线程2的线程ID:" << thdId << endl;
});
}
});
this_thread::sleep_for(chrono::seconds(2));
getchar();
pool.Stop();
thd1.join();
thd2.join();
}
测试结果: