1

As a part of a uni project I have to create a program which can have an arbitrary amount of threads given as a command line argument. I first tried making a dynamic array of threads like this: thread* threads = new thread[numThreads]; ( Note: I want to use the threads class, not pthreads ). I figured it didn't work because to my knowledge new tries to call default constructors to thread, which it doesn't have and lator on I cannot actually construct the threads properly. Then I tried to do it in the following way:

thread** threads = new thread*[numThreads];
for (int i = 0; i < numThreads; i++)
    {
        threads[i] = new thread(calculateFractal, width, height, numThreads, i, fractal, xmin, xmax, ymin, ymax, xStepSize, yStepSize, maxNorm);
    }

I have defined the function and all of the used variables in the aforementioned constructors in the for are of their appropriate data types:

void calculateFractal(int& width, int& height, int& numThreads, int& thisThreadNum, RGB**& fractal, 
    long double& xmin, long double& xmax,long double& ymin, long double& ymax,
    long double& xStepSize, long double& yStepSize, long double& maxNorm)

This code still doesn't work and gives the same compiler errors(C2672 and C2893) for essentially inappropriate function template as if I have not passed the correct type of arguments. Can you figure out what is wrong with the code?

5
  • 1
    vector<thread> threads(num_threads, thread(calculateFractal, width, height, numThreads, i, fractal, xmin, xmax, ymin, ymax, xStepSize, yStepSize, maxNorm)); would be the first thing I'd try. Commented Jul 5, 2020 at 6:54
  • Actually that's not true. The first thing I'd try is to create one thread, to make sure I'd got the thread function and it's parameters correct. thread a_thread(calculateFractal, width, height, numThreads, i, fractal, xmin, xmax, ymin, ymax, xStepSize, yStepSize, maxNorm);. Have you tried that? Commented Jul 5, 2020 at 6:58
  • I think the problem is the reference arguments. From cppreference The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with std::ref or std::cref). Commented Jul 5, 2020 at 7:01
  • std::thread does have a default constructor so your first approach (although better done with a vector) should work. Please show a minimal reproducible example with the full code and full error message Commented Jul 5, 2020 at 7:09
  • Why the reference parameters? The function is just going to write into fractal, isn't it? Commented Jul 5, 2020 at 7:11

2 Answers 2

2

Use std::vector<std::thread>, as follows

std::vector<std::thread> threadsVec(threadsNumber);
for(size_t i{}; i < threadsNumber; ++i){
    threadsVec[i] = std::thread{.....};
}

and when you put the args make sure you use std::ref(arg) when your function need a reference because std::thread takes rvalues only, hence you have to introduce an std::reference_wrapper

The following is a complete working example

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

struct RGB{};

void calculateFractal(int& width, int& height, int& numThreads, int& thisThreadNum, RGB**& fractal,
                      long double& xmin, long double& xmax,long double& ymin, long double& ymax,
                      long double& xStepSize, long double& yStepSize, long double& maxNorm){
    std::cout << "inside the thread";
}
int main()
{
    int width, height, thisThreadNum;
    RGB fractal1;
    RGB* fractal2 = &fractal1;
    RGB** fractal3 = &fractal2;
    long double xmin, xmax, ymin, ymax, xStepSize, yStepSize, maxNorm;

    int threadsNumber = 1;
    std::vector<std::thread> threadsVec(threadsNumber);
    for(size_t i{}; i < threadsNumber; ++i){
        threadsVec[i] = std::thread{calculateFractal, std::ref(width), std::ref(height),
                        std::ref(threadsNumber), std::ref(thisThreadNum), std::ref(fractal3),
                        std::ref(xmin), std::ref(xmax), std::ref(ymin), std::ref(ymax),
                        std::ref(xStepSize), std::ref(yStepSize), std::ref(maxNorm)
        };
    }


    for(size_t i{}; i < threadsNumber; ++i){
        threadsVec[i].join();
    }

}
Sign up to request clarification or add additional context in comments.

Comments

1

Use std::vector instead of C-style arrays. You need to use std::ref for the reference parameters, as std::thread otherwise doesn't know to pass them by reference:

std::vector<std::thread> threads;
threads.reserve(numThreads);
for (int i = 0; i < numThreads; i++) {
  threads.emplace_back(calculateFractal, std::ref(width), std::ref(height), std::ref(numThreads), i, std::ref(fractal),
    std::ref(xmin), std::ref(xmax), std::ref(ymin), std::ref(ymax), std::ref(xStepSize), std::ref(yStepSize), std::ref(maxNorm));
}

This allows you to store the threads efficiently in an array-like structure, while still being able to construct them one-by-one.

You pass i as a reference, as the parameter is defined as int& thisThreadNum. That means all threads will try to access the i variable, possibly after it as been modified, or even when it doesn't exist anymore, when the loop has terminated. You have to remove the & to pass it by value (and not use std::ref on it), so that each thread gets its own copy containing the individual value.

If that still doesn't work, please update the question with the exact error message, show the new code including the definition of all the variables, and whether calculateFractal is a class member function.

3 Comments

Thanks for noticing the unneeded reference as I wandered why it printed the wrong number. I have tried the solution of the upper comment and will now test this one, too.
Also, do you know why a "standard" function wouldn't have a problem running without the ref(), but when starting the thread it is required?
When you call the function directly, the variable is automatically passed per reference, as the compiler can see the function needs a reference. std::thread doesn't know whether to pass it by reference as it can't analyse the function (C++ simply doesn't support that), and tries to pass by value by default, which doesn't work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.