Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emplace back thread on vector

Tags:

c++

c++11

vector

Why this cause undefined behavior?

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

std::vector<std::thread> threads(3);

void task() { std::cout<<"Alive\n";}
void spawn() {
        for(int i=0; i<threads.size(); ++i)
                //threads[i] = std::thread(task);
                threads.emplace_back(std::thread(task));

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

int main() {
        spawn();
}

If I will create threads as in commented line thread is copied/moved assignment so its fine, but why is not working when creating thread in place?

like image 307
Mateusz Wojtczak Avatar asked Sep 01 '16 08:09

Mateusz Wojtczak


People also ask

Why does emplace_back require moveinsertable for vectors?

If T 's move constructor is not noexcept and is not CopyInsertable into *this, vector will use the throwing move constructor. If it throws, the guarantee is waived and the effects are unspecified. Since reallocation may take place, emplace_back requires the element type to be MoveInsertable for vectors.

What is emplace_back () in C++?

emplace_back () constructs a string in-place, so no temporary string will be created but rather emplace_back () will be called directly with char* argument. It will then create a string to be stored in the vector initialized with this char*. So, in this case, we avoid constructing and destroying an unnecessary temporary string object.

Does emplace_back () destroy the temporary object?

Then the temporary object will be destroyed. emplace_back () constructs a string in-place, so no temporary string will be created but rather emplace_back () will be called directly with char* argument. It will then create a string to be stored in the vector initialized with this char*.

Should vector pushback be thread safe?

There is no good reason for std::vector to make push_back thread-safe, because that would incur overhead in any single-threaded usage. Further, also with more than one thread, often you don't want synchronisation on the lowest level. Consider:


1 Answers

What is happening in your code is that you construct three default threads, then add three further threads.

Change:

std::vector<std::thread> threads(3);

To:

std::vector<std::thread> threads;
const size_t number_of_threads = 3;

int main() {
    threads.reserve(number_of_threads);
    spawn();
}

And inside spawn:

void spawn() {
    for (int i = 0; i < number_of_threads; ++i) {
        threads.emplace_back(std::thread(task));
    }
    for (int i = 0; i < threads.size(); ++i) {
        threads[i].join();
    }
}

When you are using emplace_back or push_back, you must not allocate the memory before, because that will call the constructor of threads. You should just reserve it.

BTW, since you are using emplace_back not push_back you can directly write:

threads.emplace_back(task);
like image 194
Humam Helfawi Avatar answered Sep 28 '22 08:09

Humam Helfawi