0

I am a novice in the field of C++ multithread program. I want to read block data from my disk and do some computation based on these data. In order to simplify the code, I write the following demo to test my idea. However, I found some questions.

#include <iostream>
#include <thread>
#include <string>
#include <mutex>
#include <vector>
#include <condition_variable>

std::condition_variable cv;
std::mutex cv_m;

bool is_print;

void read_value(std::vector<int> &data)
{
    for (int j = 1; j < 5; j++)
    {
        std::cout << "read data iteration is " << j << std::endl;
        std::lock_guard<std::mutex> lk(cv_m);
        for (int i = 0; i < 5; i++)
            data.at(i) = i * j;
        is_print = true;
        cv.notify_one();
    }
}

void print_value(const std::vector<int> &data)
{
    std::cout << "output data" << std::endl;
    std::unique_lock<std::mutex> lk(cv_m);
    cv.wait(lk, []{return is_print;});
    for (int i = 0; i < data.size(); i++)
        std::cout << data[i] << std::endl;
    is_print = false;
}

int main()
{
    is_print = false;
    std::vector<int> data = {0, 0, 0, 0, 0};

    std::thread thread_read(read_value, data);
    std::thread thread_print(print_value, data);

    thread_print.join();
    thread_read.join();

    return 0;
}

In this demo, I use "read_value" to simulate read data from disk and I want to read data from disk several times. So, I add an outer loop in the function "read_value". After that, I use "print_value" function to output the data. However, in such case, I meet the error as the following, which tells me that I use the deleted function. I am not sure what the problem is and how to read data several times. Thank you so much!

In file included from 

/Users/zsk/Downloads/programming/C++/multi_thread/multi_thread/main.cpp:10:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/thread:342:5: error: attempt to use a deleted function
    __invoke(_VSTD::move(_VSTD::get<1>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/thread:352:5: note: in instantiation of function template specialization 'std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(std::__1::vector<int, std::__1::allocator<int> > &), std::__1::vector<int, std::__1::allocator<int> > , 2>' requested here
    __thread_execute(*__p, _Index());
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/thread:368:47: note: in instantiation of function template specialization 'std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, void (*)(std::__1::vector<int, std::__1::allocator<int> > &), std::__1::vector<int, std::__1::allocator<int> > > >' requested here
    int __ec = __libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
                                              ^
/Users/zsk/Downloads/programming/C++/multi_thread/multi_thread/main.cpp:51:17: note: in instantiation of function template specialization 'std::__1::thread::thread<void (&)(std::__1::vector<int, std::__1::allocator<int> > &), std::__1::vector<int, std::__1::allocator<int> > &, void>' requested here
    std::thread thread_read(read_value, data);

2 Answers 2

5

The problem is that the std::thread object needs to be able to copy the arguments you pass to the threads. And references can't be copied.

To solve this you need to use std::ref or std::cref to wrap the arguments:

std::thread thread_read(read_value, std::ref(data));
std::thread thread_print(print_value, std::cref(data));
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you so much! Actually, there is one more question. I fix my code as what you suggest and then, I found that the output result is not my expectation. I am not sure how to make the "read_value" function to nofiry aonther thread several times.
@Sean Take a look at the print_value thread function, how many times does it wait for the signal? Move the lock and the wait into the loop instead. Might need some other way of handling thread termination though.
Thank you so much and I will check it again.
@Someprogrammerdude Just to be correct - constructor of std::thread does not copy the arguments all the times, it might move them as well, if these are rvalues and provide move constructors.
0

Working with threads is surprising if you try to use references. The other answer is completely right, use std::ref to pass the arguments.

Personally, I prefer to use lambdas instead:

std::thread thread_read([&data](){ read_value(data); });
std::thread thread_print([&data = std::as_const(data)](){ print_value(data); });

It might not be as elegant as the std::ref though it uses the concepts you already know from all other places instead of requiring you to remember the unexpected copying.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.