模板类内部静态成员的延迟初始化

GJ代码

嗨,我是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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章