嗨,我是C ++的新手,我正在尝试实现线程池,这是因为我正在尝试修复一些C ++概念。这是到目前为止我写的:
#include <condition_variable>
#include <functional>
#include <future>
#include <mutex>
#include <optional>
#include <queue>
/**
* This class should be a singleton, that's because if
* we want to limit the amount of running threads
* we should check that there are not multiple instances
* of this class. This implementation provides guarantees
* that there will be a single instance of a given template
* specialization. This class provide also a thread safe queue.
*/
template <typename R, typename... Args> class ThreadPool {
private:
std::mutex m;
std::condition_variable cv;
bool is_running;
size_t pool_size;
std::queue<std::packaged_task<R(Args...)>> jobs;
static ThreadPool<R, Args...> *instance; // Singleton instance
ThreadPool()
: is_running{true}, pool_size{std::thread::hardware_concurrency()} {
} // the constructor should not be accessible
ThreadPool(size_t pool_size)
: is_running{true}, pool_size{pool_size} {
} // the constructor should not be accessible
public:
ThreadPool(const ThreadPool &) = delete; // copy constructor disabled;
ThreadPool &
operator=(const ThreadPool &) = delete; // copy assignment disabled
ThreadPool &
operator=(ThreadPool &&other) = delete; // movement temporary disabled
/**
* Create a thred pool with a size that it's equals to
* the number of cores on the machine. This istance
* should be use to maximize the parallelism.
*/
static ThreadPool<R, Args...> *getInstance() {
if (instance == nullptr)
instance = new ThreadPool<R, Args...>{};
return ThreadPool::instance;
}
/**
* Create a thred pool with a size that it's equals to
* the given pool size. This istance should be use
* when we don't need to use the highest level of
* parallelism.
*
* @pool_size: desired size of the thread pool
*/
static ThreadPool<R, Args...> *getInstance(const size_t pool_size) {
if (ThreadPool::instance == nullptr)
ThreadPool::instance = new ThreadPool<R, Args...>{pool_size};
return ThreadPool::instance;
}
void submit(std::packaged_task<R(Args...)> f) {
std::unique_lock l{m};
if (is_running) {
if (jobs.size() == pool_size)
cv.wait(l, [&]() { return jobs.size() < pool_size; });
jobs.push(std::move(f));
cv.notify_one();
}
}
std::optional<std::packaged_task<R(Args...)>> get() {
std::unique_lock l{m};
if (jobs.size() == 0 && is_running)
cv.wait(l, [&]() { return jobs.size() > 0 || !is_running; });
if (jobs.size() > 0 && is_running) {
std::packaged_task<R(Args...)> f = std::move(jobs.front());
cv.notify_one();
return std::optional<std::packaged_task<R(Args...)>>{std::move(f)};
}
return std::nullopt;
}
void quit() {
// todo: valutare eccezione su quit multiple
std::unique_lock l{m};
if (is_running) {
is_running = false;
cv.notify_all();
}
}
};
int main() {
static ThreadPool<int, int, int> *t = ThreadPool<int, int, int>::getInstance();
return 0;
}
当我编译时:g++ -g -Wall -Werror -pthread -std=c++17 main.cpp -o main
它给我以下错误:
/usr/bin/ld: /tmp/cc6zwABg.o: in function `ThreadPool<int, int, int>::getInstance()':
/home/gjcode/Politecnico/CodeProjects/PDS/cpp/threadpool/threadpool.h:54: undefined reference to `ThreadPool<int, int, int>::instance'
/usr/bin/ld: /home/gjcode/Politecnico/CodeProjects/PDS/cpp/threadpool/threadpool.h:55: undefined reference to `ThreadPool<int, int, int>::instance'
/usr/bin/ld: /home/gjcode/Politecnico/CodeProjects/PDS/cpp/threadpool/threadpool.h:56: undefined reference to `ThreadPool<int, int, int>::instance'
collect2: error: ld returned 1 exit status
它似乎与链接阶段有关,我试图cppinsights
用来查看模板的初始化方式,以及它似乎正常工作。为什么我不能访问静态成员instance
?我也尝试在公共区域移动该字段,但这没有用。
您忘记了定义instance
类的外部定义:
template <typename R, typename... Args>
ThreadPool<R, Args...>* ThreadPool<R, Args...>::instance = nullptr;
意见:具有两种创建实例的方式有些奇怪。如果按此顺序拨打电话:
static ThreadPool<R, Args...> *getInstance();
static ThreadPool<R, Args...> *getInstance(const size_t pool_size);
...您将获得一个默认值pool_size
,如果您使用默认值,则会得到一个用户定义的pool_size
。我建议选择其中一种并将其移至instance
实际getInstance()
方法。您可以使pool_size成为模板参数,而不用两种实例化单例的方法。
如果您希望两个保留两种构造方式,则可以执行以下操作:
static ThreadPool<R, Args...>& getInstance(const size_t pool_size) {
static ThreadPool<R, Args...> instance(pool_size);
return instance;
}
static ThreadPool<R, Args...>& getInstance() {
return getInstance(std::thread::hardware_concurrency());
}
请注意,它返回一个引用。这种方式有一些好处:
delete
以后没有必要了(您在当前的实现中也已经忘记了)。nullptr
。本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句