-1

I'm trying to change a vector in a different thread, but the value of the vector is not changed. I thought that using std::ref will fix the issue but it didn't work.

This is the code that start the threads:

printf("tmp size: %d\n", tmp_size);
printf("before change");
printArray(tmp);
std::thread threads[1];
for(int i = 0; i < 1; i++){
    threads[i] = std::thread(callback,  std::ref(tmp));
}

for(int i = 0; i < 1; i++){
    threads[i].join();
}

printf("after join: ");
printArray(tmp);

this is the callback:

void callback(std::vector<uint64_t>  tmp){

    tmp[0] = 1;
    printf("inside callback");
    printArray(tmp);
}

and the output is:

tmp size: 2
before change 0 0
inside callback 1 0
after join:  0 0

I was expecting that after the thread change the vector the values will be: inside callback: 1 0. Isn't it passed by reference?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
darc
  • 530
  • 4
  • 15
  • What are you trying to do? Are all your threads doing the same thing? – curiousguy Oct 27 '18 at 22:34
  • I'm trying to do parallel merge sort. but the output is using only 1 thread .. parallel_level=1 – darc Oct 27 '18 at 22:36
  • You post code that is impossible to comprehend. What is left, mid, right? – curiousguy Oct 27 '18 at 22:42
  • posted simpler code, the issue is changing the value inside the thread. – darc Oct 27 '18 at 23:07
  • 3
    The `callback` function takes its parameter by value, so it will never modify the caller's vector. You need to change `callback` to take its parameter by reference. You are passing it a reference, but then it is taking that reference by value. Oops. – David Schwartz Oct 27 '18 at 23:10
  • thank you David, can you post an example? when I tried to change the callback signature to void callback(std::vector &tmp) it didn't compile. doesn't std::ref means pass by reference? – darc Oct 27 '18 at 23:22
  • @darc Yes, `std::ref` means pass by reference. But then the callback function takes that reference by value, getting the value of the reference. Here's a [working example](https://onlinegdb.com/BJmMBuM3m). – David Schwartz Oct 27 '18 at 23:30

2 Answers2

1

You are passing a reference to the function, but then the function takes its parameter by value, giving it the value of the reference. Modifying the value of the reference does no good. You need to modify the reference. Here's a demonstration of how to do it correctly:

#include <vector>
#include <stdint.h>
#include <thread>

void callback(std::vector<uint64_t> &tmp)
{
    tmp[0] += 1;
}

int main()
{
    std::thread threads[1];
    std::vector<uint64_t> tmp;
    tmp.push_back(1);
    for(int i = 0; i < 1; i++)
        threads[i] = std::thread(callback,  std::ref(tmp));

    for(int i = 0; i < 1; i++)
        threads[i].join();
    printf("%d\n", (int) tmp[0]);
}
David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

If you wanted the callback to change the vector, you would have to pass it by pointer or reference.

Your callback code has made a copy of it instead.

Another option that can sometimes be more thread-safe is if you were to "move" the vector into the thread and then move it back out when the thread finishes. Like so:

#include <thread>
#include <future>
#include <vector>
#include <iostream>

std::vector<int> addtovec(std::vector<int> vec, int add) {
    for(auto &x: vec) {
        x += add;
    }
    return vec;
}

std::ostream& operator<<(std::ostream& os, const std::vector<int> &v) {
    os << '{';
    bool comma = false;
    for(const auto &x: v) {
        if(comma) os << ',';
        comma = true;
        os << x;
    }
    os << '}';
    return os;
}

int main() {
    std::vector<int> a{1,2,3,9,8,7};
    std::cout << "before: " << a << std::endl;

    auto future = std::async(addtovec, std::move(a), 5);
    std::cout << "after move: " << a << std::endl;
    a = future.get();

    std::cout << "after get: " << a << std::endl;
    return 0;
}
Zan Lynx
  • 53,022
  • 10
  • 79
  • 131