如何在 C++ 14 的类中启动线程?

Posted

技术标签:

【中文标题】如何在 C++ 14 的类中启动线程?【英文标题】:How to initiate a thread in a class in 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 线程。 【参考方案1】:

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

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

;

//...

ThreadOne::ThreadOne() 
    thread = std::threadRealThread, 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() 将永远等待。

【讨论】:

感谢您的详细解释和示例代码!

以上是关于如何在 C++ 14 的类中启动线程?的主要内容,如果未能解决你的问题,请参考以下文章

c++ 如何在构造函数中启动一个线程,从命名管道读取数据?

如何在 C++ 中运行具有仅调用线程的函数的类的多个对象?

如何在 C++ 中的类中递归调用函数方法?

如何在不等待 C++ 响应的情况下启动线程?

如何在 C++ 中的类中返回对象的字符串? [关闭]

在 C++ 中的类中初始化与公共和私有相同的函数:它是如何工作的?