【问题标题】:How to initiate a thread in a class in C++ 14?如何在 C++ 14 的类中启动线程?
【发布时间】:2019-12-20 15:28:42
【问题描述】:
class ThreadOne {
public:
    ThreadOne();
    void RealThread();
    void EnqueueJob(s_info job);

    std::queue<s_info> q_jobs;

private:
    H5::H5File* targetFile = new H5::H5File("file.h5", H5F_ACC_TRUNC);
    std::condition_variable cv_condition;
    std::mutex m_job_q_;
};

ThreadOne::ThreadOne() {
}

void ThreadOne::RealThread() {
    while (true) {
        std::unique_lock<std::mutex> lock(m_job_q_);
        cv_condition.wait(lock, [this]() { return !this->q_jobs.empty(); });

        s_info info = std::move(q_jobs.front());
        q_jobs.pop();
        lock.unlock();      
        //* DO THE JOB *//  
    }
}

void ThreadOne::EnqueueJob(s_info job) {
    {
        std::lock_guard<std::mutex> lock(m_job_q_);
        q_jobs.push(std::move(job));
    }
    cv_condition.notify_one();
}

ThreadOne *tWrite = new ThreadOne();

我想创建一个线程并将一个数组指针及其名称作为结构(s_info)发送给它,然后让线程将其写入文件。我认为这比在需要写作的时候创建一个线程要好。

我可以创建一个线程池并为其分配作业,但在我的情况下不允许同时写入同一个文件,我认为只创建一个线程就足够了,程序仍然会执行 CPU 密集型作业写作工作正在进行中。

总而言之,这个类(希望)获取数组指针及其数据集名称,将它们放入q_jobsRealThread 将数组写入文件。

我提到了一个 C++ 线程池程序,该程序像这样启动线程:

std::vector<std::thread> vec_worker_threads;
vector_worker_threads.reserve(num_threads_);
vector_worker_threads.emplace_back([this]() { this->RealThread(); });

我是 C++ 新手,我了解上面的代码的作用,但我不知道如何在没有向量的情况下在我的班级中启动 RealThread。我怎样才能创建一个类的实例,其中包含一个已经准备好的线程(RealThread)?

【问题讨论】:

  • 我不确定我是否完全掌握了困难的本质。如果你需要一个单线程,那么只需要一个std::thread 类型的变量。如果需要,该变量可以是某个类的成员;例如甚至可以成为ThreadOne 的成员。
  • @Igor Tandetnik 谢谢你的评论。你能举个例子吗?我记得读过你不能像在 main() 中使用函数那样只在类的实例中创建线程。
  • @maynull "我记得读过你不能像使用 main() 中的函数那样在类的实例中创建线程" 为什么?你是从哪里“记住”这个的?
  • class ThreadOne {std::thread thread_; void StartThread() { thread_ = std::thread([this]{ RealThread(); }); } }; 类似的东西。
  • @IgorTandetnik 但是,不要忘记在析构函数中join 线程。

标签: c++ multithreading concurrency


【解决方案1】:

据我所知,正如在 cmets 中已经讨论的那样,您只需要 ThreadOnestd::thread 成员:

class ThreadOne {
    std::thread thread;
public:
    ~ThreadOne();
    //...

};

//...

ThreadOne::ThreadOne() {
    thread = std::thread{RealThread, this};
}

ThreadOne::~ThreadOne() {
    // (potentially) notify thread to finish first
    if(thread.joinable())
        thread.join();
}    

//...

ThreadOne tWrite;

请注意,我没有在构造函数的member-initializer-list中启动线程,以避免线程访问其他尚未初始化的成员。 (std::thread的默认构造函数不会启动任何线程。)

我还写了一个析构函数,它将等待线程完成并加入它。在销毁附加到它的std::thread 对象之前,您必须始终加入线程,否则您的程序将调用std::terminate 并中止。

最后,我将tWrite 从一个指针直接替换为一个类类型。您可能没有理由在那里使用动态分配,即使您需要它,您也应该使用

auto tWrite = std::make_unique<ThreadOne>();

或等效的,这样您就不会依赖手动delete将指针指向正确的位置。

另请注意,您当前的 RealThread 函数似乎永远不会完成。它必须在某个时候返回,可能是在收到主线程的通知之后,否则thread.join() 将永远等待。

【讨论】:

  • 感谢您的详细解释和示例代码!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 2012-03-26
相关资源
最近更新 更多