Search code examples
c++multithreadingmethodsstatic-methods

Thread calling function with non-static members failing


I created a function void top() to render out an image by sending a ray for each pixel. I wanted to put it on a thread. I used #include <thread> library but when I declared the thread in the main() method it gave me two errors: Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept() and Error C2672 'std::invoke': no matching overloaded function. I think it could possibly be because void top() calls both non-static and static methods. Just learning about threading so a bit confused about what is wrong. All the functions below are inside the main cpp file.

void top(int& samples_per_pixel, camera& cam, const color& background, hittable& world, const int& max_depth) {
    for (float j = image_height - 1; j >= image_height/2; --j) {
        for (int i = 0; i < image_width; ++i) {
            color pixel_color(0, 0, 0);
            for (int s = 0; s < samples_per_pixel; ++s) {
                auto u = (i + random_double()) / (image_width - 1); //Random double is static. From other header file
                auto v = (j + random_double()) / (image_height - 1);
                ray r = cam.get_ray(u, v); //get_ray() is non-static and in camera class
                pixel_color += ray_color(r, background, world, max_depth); //Ray_color defined above top() method in same main cpp file
                pixel_color += color(0, 0, 0);
            }

            auto r = pixel_color.x();
            auto g = pixel_color.y();
            auto b = pixel_color.z();

            auto scale = 1.0 / samples_per_pixel;
            r = sqrt(scale * r);
            g = sqrt(scale * g);
            b = sqrt(scale * b);

            int ir = static_cast<int>(256 * clamp(r, 0.0, 0.999));
            int ig = static_cast<int>(256 * clamp(g, 0.0, 0.999));
            int ib = static_cast<int>(256 * clamp(b, 0.0, 0.999));

            pixels[index++] = ir; //pixels defined above top() class
            pixels[index++] = ig;
            pixels[index++] = ib;

        }

    }
}

...

int main(){
...

std::thread first(top,samples_per_pixel, cam, background, world, max_depth); //Two errors being called here
first.detach();

}


Solution

  • From `std::thread::thread:

    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).

    So, just wrap each variable that you take by reference in one of the wrappers. Prefer std::cref if you are not changing the value inside he thread and adjust your function's signature accordingly.

    Instead of passing a const int&, just pass an int.

    Example:

    // new signature:
    void top(int samples_per_pixel, camera& cam, const color& background,
             hittable& world, int max_depth);
    
    // new starting call:
    std::thread first(top, samples_per_pixel, std::ref(cam), std::cref(background),
                      std::ref(world), max_depth);