0

Can anybody explain me why

void doSomething(vector<int>& vec) {
    for (int i = 0; i < 100; ++i)
        vec.push_back(i);
}

int main(int argc, char** argv) {
    vector<int> v;
    thread t1(doSomething, v);
    thread t2(doSomething, v);
    t2.join();
    t1.join();
    cout << v.size() << endl;
    return 0;
}

prints 0, while the same thing with a pointer prints 200

void doSomething(vector<int>* vec) {
    for (int i = 0; i < 100; ++i)
        vec->push_back(i);
}

int main(int argc, char** argv) {
    vector<int>* v = new vector<int>();
    thread t1(doSomething, v);
    thread t2(doSomething, v);
    t2.join();
    t1.join();
    cout << v->size() << endl;
    return 0;
}

Shouldn't working on a reference be equal (to working on a pointer) here?

Edit: it's not thread-safe on purpose

Can you provide me with a reference as to why do I need to use std::ref?

mewa
  • 1,532
  • 1
  • 12
  • 20
  • 1
    You are lucky that you get anything at all. You have two threads, one vector and no locking. Anything could happen. – Zan Lynx Jul 24 '14 at 23:24
  • @ZanLynx with the pointer version, absolutely. with the reference version it's actually quite safe, if not what the OP expected, as explained in the linked duplicate. – aruisdante Jul 24 '14 at 23:25
  • @aruisdante: True. If it worked like mewa expected it would have the same problem. – Zan Lynx Jul 24 '14 at 23:26
  • @ZanLynx I did it on purpose, I was trying to see what can happen when concurrent modifications occur – mewa Jul 24 '14 at 23:27

2 Answers2

2

1) Your code is not thread safe (concurrent push_back on a vector)

2) Arguments are passed by value by default to std::thread. This semantic of copying the arguments is natural with threads : any argument will be copied/moved to thread-accessible storage. Doing so, the std:::thread does its best to avoid concurrency access to shared objects.

Use std::ref to pass an argument by reference to your thread callable :

thread t1(doSomething, std::ref(v));
thread t2(doSomething, std::ref(v));
                        ^^^^^^^^

Without std::ref, neither gcc or clang compile this code.


For future reference, std::thread constructors are described in section § 30.3.1.2 of the C++ standard.

quantdev
  • 23,517
  • 5
  • 55
  • 88
  • Could you post a reference with explanation why? Also, it made it with msvc – mewa Jul 24 '14 at 23:40
  • 1
    @mewa there's an explanation in the links in this answer. Both `code highlighs` before the main snipper are links to the respective templates. Check the constructor of `std::thread` for the reference – Paweł Stawarz Jul 24 '14 at 23:47
  • Yes. I also edited to explain a little more. basically, `std::thread` use copy semantics on the argument to avoid (by default) working on shared objects. – quantdev Jul 24 '14 at 23:48
1

std::thread unfortunately takes parameters by value. Even if you set it up to take by reference, it still ends up copying it. You can use std::ref to pass by reference.