maynull
maynull

Reputation: 2046

How to initiate a thread in a class in C++ 14?

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();

I want to make a thread and send it a pointer of an array and its name as a struct(s_info), and then make the thread write it into a file. I think that it's better than creating a thread whenever writing is needed.

I could make a thread pool and allocate jobs to it, but it's not allowed to write the same file concurrently in my situation, I think that just making a thread will be enough and the program will still do CPU-bound jobs when writing job is in process.

To sum up, this class (hopefully) gets array pointers and their dataset names, puts them in q_jobs and RealThread writes the arrays into a file.

I referred to a C++ thread pool program and the program initiates threads like this:

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

I'm new to C++ and I understand what the code above does, but I don't know how to initiate RealThread in my class without a vector. How can I make an instance of the class that has a thread(RealThread) that's already ready inside it?

Upvotes: 0

Views: 512

Answers (1)

walnut
walnut

Reputation: 22162

From what I can gather, and as already discussed in the comments, you simply want a std::thread member for ThreadOne:

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;

Note that I did not start the thread in the member-initializer-list of the constructor in order to avoid the thread accessing other members that have not been initialized yet. (The default constructor of std::thread does not start any thread.)

I also wrote a destructor which will wait for the thread to finish and join it. You must always join threads before destroying the std::thread object attached to it, otherwise your program will call std::terminate and abort.

Finally, I replaced tWrite from being a pointer to being a class type directly. There is probably no reason for you to use dynamic allocation there and even if you have a need for it, you should be using

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

or equivalent, instead, so that you are not going to rely on manually deleteing the pointer at the correct place.

Also note that your current RealThread function seems to never finish. It must return at some point, probably after receiving a notification from the main thread, otherwise thread.join() will wait forever.

Upvotes: 2

Related Questions