Ermando
Ermando

Reputation: 235

C++ threads inside a 'for' loop print wrong values

I'm trying to understand multithreading in C++, but I’m stuck in this problem: if I launch threads in a for loop they print wrong values. This is the code:

#include <iostream>
#include <list>
#include <thread>

void print_id(int id){
    printf("Hello from thread %d\n", id);
}

int main() {
    int n=5;
    std::list<std::thread> threads={};
    for(int i=0; i<n; i++ ){
        threads.emplace_back(std::thread([&](){ print_id(i); }));
    }
    for(auto& t: threads){
        t.join();
    }
    return 0;
}

I was expecting to get printed the values 0,1,2,3,4 but I often got the same value twice. This is the output:

Hello from thread 2
Hello from thread 3
Hello from thread 3
Hello from thread 4
Hello from thread 5

What am I missing?

Upvotes: 20

Views: 1822

Answers (4)

Guillermo Solana
Guillermo Solana

Reputation: 247

With c++17 you can do:

void foo(int param)
{
  //something
}

main()
{
    std::vector<std::thread> threadList;

    for (int i = 0; i < 100; i++)
    {
        threadList.push_back( std::thread(foo, 2) );

    }
    
    for (auto& thread : threadList)
    {
        thread.join();
    }
}

Upvotes: 0

Landstalker
Landstalker

Reputation: 1368

Another thing:

Do not wait until to have always an ordered sequence: 0, 1, 2, 3, ... because the multithreading execution mode has a specificity: indeterminism.

Indeterminism means that the execution of the same program, under the same conditions, gives a different result.

This is due to the fact that the OS schedules threads differently from one execution to another depending on several parameters: CPU load, priority of other processes, possible system interruptions, etc.

Your example contains only five threads, so it's simple. Try to increase the number of threads, and for example put a sleep in the processing function. You will see that the result can be different from one execution to another.

Upvotes: 5

Bathsheba
Bathsheba

Reputation: 234695

The [&] syntax is causing i to be captured by reference. So quite often therefore i will be further advanced when the thread runs than you might expect. More seriously, the behaviour of your code is undefined if i goes out of scope before a thread runs.

Capturing i by value - i.e. std::thread([i](){ print_id(i); }) is the fix.

Upvotes: 19

Some programmer dude
Some programmer dude

Reputation: 409176

Two problems:

  1. You have no control over when the thread runs, which means the value of the variable i in the lambda might not be what you expect.

  2. The variable i is local for the loop and the loop only. If the loop finishes before one or more thread runs, those threads will have an invalid reference to a variable whose lifetime have ended.

You can solve both these problems very simply by capturing the variable i by value instead of by reference. That means each thread will have a copy of the value, and that copy will be made uniquely for each thread.

Upvotes: 7

Related Questions