简体   繁体   中英

C++ threads. Why always executes last thread?

Why only last threads executes every time? I'm trying to divide grid into N workers, half of grid always not touchable and other part always proceed by 1 last created thread. Should I use an array instead of vector? Locks also do not help to resolve this problem.

#include <iostream>
#include <unistd.h>
#include <vector>

#include <stdio.h>
#include <cstring>

#include <future>
#include <thread> 
#include <pthread.h>

#include <mutex>

using namespace std;

std::mutex m;

int main(int argc, char * argv[]) {

  int iterations = atoi(argv[1]), workers = atoi(argv[2]), x = atoi(argv[3]), y = atoi(argv[4]);

  vector<vector<int> > grid( x , vector<int> (y, 0));
  std::vector<thread> threads(workers);

  int start, end, lastworker, nwork;

  int chunkSize = y/workers;

  for(int t = 0; t < workers; t++){

    start = t * chunkSize;
    end = start + chunkSize;

    nwork = t;

    lastworker = workers - 1;

    if(lastworker == t){
      end = y; nwork = workers - 1;
    }

threads[nwork] = thread([&start, &end, &x, &grid, &t, &nwork, &threads] {

                cout << " ENTER TO THREAD -> " << threads[nwork].get_id() << endl;

    for (int i = start; i < end; ++i)
                {
                    for (int j = 0; j < x; ++j)
                    {
                      grid[i][j] = t;

                    }              
                }

                sleep(2);
        });
cout << threads[nwork].get_id() << endl;

}

for(auto& th : threads){
 th.join();
}

    for (int i = 0; i < y; ++i)
    {
        for (int j = 0; j < x; ++j)
        {
          cout << grid[i][j];

        }
        cout << endl;
    } 

  return(0);
}
[&start, &end, &x, &grid, &t, &nwork, &threads]

This line is the root of the problem. You are capturing all the variables by reference, which is not what you want to do.

As a consequence, each thread uses the same variables, which is also not what you want.

You should only capture grid and threads by reference, the other variables should be captured by value ('copied' into the lambda)

[start, end, x, &grid, t, nwork, &threads]

Also, you are accessing grid wrong everywhere: change grid[i][j] to grid[j][i]

thread([&start, &end, &x, &grid, &t, &nwork, &threads] {
                                     =======

The lambda closure that gets executed by every thread captures a reference to nwork .

Which means that as the for loop iterates and starts every thread, each captured thread will always reference the current value of nwork , at the time it does.

As such, the outer loop probably quickly finishes creating each thread object before all the threads actually initialize and actually enter the lambda closure, and each closure sees the same value of nwork , because it is captured by reference , which is the last thread id.

You need to capture nwork by value instead of by reference.

You're passing all the thread parameters are references to the thread lambda. However, when the loop continues in the main thread, the thread parameter variables change, which changes their values in the threads as well, messing up all the previously-created threads.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM