我想尝试实现我自己版本的C++线程池(我知道有很多..)。
我希望有人能知道我是否做得还好。
塔斯克h:
#pragma once
#include <memory>
#include <queue>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include "../Worker/Worker.h"
class Tasker
{
public:
// Default Tasker Constructor.
Tasker(const unsigned int & newTaskerThreadCount)
{
// Construct the Vector of Threads. By default, each of these will not have any thread associated.
mTaskerThreads = std::vector<std::thread>(newTaskerThreadCount);
}
// Default Tasker Destructor, waits for all the workers to complete.
virtual ~Tasker()
{
end();
}
// Add Worker to the List of Workers to Execute.
inline virtual void addWorker(std::shared_ptr<Worker> newWorker)
{
// Create a unique lock.
std::unique_lock<std::mutex> lockWorkers(mWorkersMutex);
// Add a worker.
mWorkers.push(newWorker);
// Release the lock.
lockWorkers.release();
// Notify all waiting threads.
mWorkersCB.notify_all();
}
// Begin executing any workers in the queue.
inline virtual void begin()
{
//
mIsActive = true;
// Create all the Threads.
for (unsigned int i = 0; i < mTaskerThreads.size(); i++)
{
mTaskerThreads[i] = std::thread(&Tasker::executeWorker, this);
}
}
// End the execution, waiting for all the workers in the queue to complete.
inline virtual void end()
{
//
mIsEnd = true;
// Create a unique lock.
std::unique_lock<std::mutex> lockWorkers(mWorkersMutex);
// Wait forever.
while (true)
{
// Lock the Workers.
if (!lockWorkers.owns_lock())
{
lockWorkers.lock();
}
// Check if all the work is finished.
if (mWorkers.size() == 0)
{
// Wait for all the threads to finish.
for (unsigned int i = 0; i < mTaskerThreads.size(); i++)
{
// Wait for a thread to finish.
mTaskerThreads[i].join();
}
}
// Unlock the Workers Mutex.
lockWorkers.release();
}
// No longer active.
mIsActive = false;
// No longer end.
mIsEnd = false;
}
private:
// Execute the Work on a Thread.
inline virtual void executeWorker()
{
// Create a unique lock.
std::unique_lock<std::mutex> lockWorkers(mWorkersMutex);
//
while (true)
{
// Lock the Workers.
if (!lockWorkers.owns_lock())
{
lockWorkers.lock();
}
// Check if we have any work.
if (mWorkers.size() > 0)
{
// Get the first available work.
std::shared_ptr<Worker> worker = mWorkers.front();
// Remove it from the queue.
mWorkers.pop();
// Release the lock.
lockWorkers.release();
// Execute the Work.
if (worker != nullptr)
{
worker->executeWork();
}
}
else
{
//
if (mIsEnd)
{
// Release the lock.
lockWorkers.release();
// Break.
break;
}
else
{
// Release the lock and wait.
mWorkersCB.wait(lockWorkers);
}
}
}
}
// The Vector of Tasker Threads.
std::vector<std::thread> mTaskerThreads;
// The Mutex for the Vector of Workers.
std::mutex mWorkersMutex;
// The Vector of Work Assignments.
std::queue<std::shared_ptr<Worker>> mWorkers;
// Whether or not the Tasker is active.
std::atomic_bool mIsActive = false;
// Whether or not the Tasker is ending.
std::atomic_bool mIsEnd = false;
// Condition Variable the Workers wait on.
std::condition_variable mWorkersCB;
};工作人员:
#pragma once
class Worker
{
public:
// Default Worker Constructor.
Worker() = default;
// Default Worker Destructor.
virtual ~Worker() = default;
// Execute the Work.
virtual void executeWork() = 0;
private:
};发布于 2017-09-11 17:55:15
end()需要以某种方式完成。
如果只在析构函数中调用end(),那么您就可以保证此时没有其他人与对象交互。这样就可以简单地说:
for (auto& thread : mTaskerThreads)
{
// Wait for a thread to finish.
thread.join();
}Tasker的构造函数应该如下所示:
Tasker(const unsigned int & newTaskerThreadCount)
: mTaskerThreads(newTaskerThreadCount) {}否则,您的向量将被设置为默认状态,然后被一个新的向量踩下。通过在列表中初始化它,它将直接进入最后的状态。
中定义的函数是隐式的。
inline virtual void addWorker(std::shared_ptr<Worker> newWorker) {...}
^^^^^^
redundant它要干净得多,更重要的是,不容易出错。
for (unsigned int i = 0; i < mTaskerThreads.size(); i++)
//vs
for(auto& thread : mTaskerThreads) {...}进行比较
if (mWorkers.size() == 0)
//vs
if (mWorkers.empty())只有要重载的函数才应该是虚拟的。据我所知,Tasker中的任何函数都不是这样的。摆脱虚拟的。
传递小类型
在传递大型结构时,const type &有时可以提供很大的节省,但是对于核心类型,您实际上是在限制编译器。
Tasker(const unsigned int& newTaskerThreadCount);
//vs
Tasker(unsigned int newTaskerThreadCount);我将摆脱begin()和end()函数,只需在构造/销毁时实现它们,这将大大简化逻辑(完全摆脱mActive和mEnded,并使清理变得更简单)。告诉类的用户通过生命周期和作用域来管理这个周期是绝对好的。
如果您不添加任何其他构造函数,这就间接地为您完成了。
)
虽然#pragma once得到了广泛的支持,但它并不是该语言的一部分。如果您正在制作一个通用的、可移植的工具,您应该避免使用它。
https://codereview.stackexchange.com/questions/175339
复制相似问题