thread-pool: Cannot be used inside the class

I found out that I can’t call threadpool inside class. If I call it in main function in app (like your example) or in dll like this:

void sleep_half_second(const size_t& i, synced_stream* sync_out)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    sync_out->println("Task ", i, " done.");
}

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    thread_pool* pool;
    synced_stream sync_out;
    int i = 1;
    pool = new thread_pool(12);
    pool->push_task(sleep_half_second, i, &sync_out);

    return TRUE;
}

It’s OK, doesn’t generate error c2064. But if using it in class, it still generates error c2064.

Please help me fix this, I need to call it inside the class

doubleRsi.zip Thank you very much

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 17 (7 by maintainers)

Most upvoted comments

Good thanks! I just wanted to confirm that you didn’t find some other tweaks/fixes.

Both Clang and MSVC require & to get a function pointer, as well as writing the full name of the function, i.e. &class:function, even when calling it from another member function.

Duely noted !

Glad to hear that! Please feel free to let me know if you have any more suggestions or feature requests 😃

PS: After doing some testing I realized the difference between test_object and &test_object in the second argument. The former will create a copy of the object, while the latter will be a pointer to the actual object. This difference is extremely important when making changes to the object, since any changes made to the copy will not be made in the original object. I corrected the code above to fix that.

Okay, I managed to make submit() work as well:

    template <typename F, typename... A, typename R = std::invoke_result_t<std::decay_t<F>, std::decay_t<A>...>>
    [[nodiscard]] std::future<R> submit(F&& task, A&&... args)
    {
        std::function<R()> task_function = std::bind(std::forward<F>(task), std::forward<A>(args)...);
        std::shared_ptr<std::promise<R>> task_promise = std::make_shared<std::promise<R>>();
        push_task(
            [task_function, task_promise]
            {
                try
                {
                    if constexpr (std::is_void_v<R>)
                    {
                        std::invoke(task_function);
                        task_promise->set_value();
                    }
                    else
                    {
                        task_promise->set_value(std::invoke(task_function));
                    }
                }
                catch (...)
                {
                    try
                    {
                        task_promise->set_exception(std::current_exception());
                    }
                    catch (...)
                    {
                    }
                }
            });
        return task_promise->get_future();
    }

Here’s the updated test program:

#include "BS_thread_pool.hpp"

BS::synced_stream sync_out;
BS::thread_pool pool;

class test
{
public:
    test(const char* string)
    {
        my_string = string;
    }

    void println(const char* string) const
    {
        sync_out.println(string);
    }

    void print_my_string() const
    {
        pool.push_task(&test::println, this, my_string);
        pool.submit(&test::println, this, my_string).wait();
    }

private:
    const char* my_string = nullptr;
};

int main()
{
    test test_object("Printed from the test object.");
    pool.push_task(&test::println, &test_object, "Printed from main().");
    pool.submit(&test::println, &test_object, "Printed from main().").wait();
    test_object.print_my_string();
}

I will incorporate this into the next release, along with a few other changes I’ve been working on.

EDIT: Fixed the above test program so it works with all compilers (previously it only worked with GCC).

Thank you very much, I have successfully compiled with lambda

	pool->push_task([=] { sleep_half_second(i); });
}

void doubleRsi::sleep_half_second(const size_t& i)
{
	std::this_thread::sleep_for(std::chrono::milliseconds(500));
}