Функтор, защищенный std::mutex с помощью оболочки

struct foo
{
    void operator()(int count, std::mutex& guard)
    {
        for (int i = 0; i < count + 1; ++i)
        {
            guard.lock();
            std::cout << i << '\t' << std::this_thread::get_id() << '\n';
            guard.unlock();
        }
    }
};

struct wruper_foo
{
    void operator()(int count)
    {
        f(count, guard);
    }

private:
    std::mutex guard;
    foo f;
};


int main()
{
    std::vector<std::thread> thrs;
    
    wruper_foo functor;

    for (int i = 0; i < 3; ++i)
    {
        thrs.push_back(std::move(std::thread(functor, i)));
    }

    for (auto& thr : thrs)
    {
        if (thr.joinable())
            thr.join();
    }
}

код выдает ошибку: std::tuple<wruper_foo,int>::tuple: нет перегруженной функции, принимающей 2 аргументов

Прошу помощи разобраться, что я делаю не так?


Ответы (2 шт):

Автор решения: Damir Hakimof
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

struct foo {
    void operator()(int count, std::mutex& guard) {
        for (int i = 0; i < count + 1; ++i) {
            std::lock_guard<std::mutex> lock(guard);
            std::cout << i << '\t' << std::this_thread::get_id() << '\n';
        }
    }
};

struct wruper_foo {
    void operator()(int count) {
        f(count, guard);
    }

private:
    std::mutex guard;
    foo f;
};

int main() {
    std::vector<std::thread> thrs;
    thrs.reserve(3);

    wruper_foo functor;

    for (int i = 0; i < 3; ++i) {
        thrs.emplace_back(std::ref(functor), i);
    }

    for (auto& thr : thrs) {
        if (thr.joinable()) {
            thr.join();
        }
    }
}
→ Ссылка
Автор решения: user7860670

Более лаконичный вариант без создания дополнительных классов, держащих состояние, но с использованием jthread, который в RAII стиле автоматически ожидает завершения потока в деструкторе. Важно, что вектор уничтожается строго до мьютекса, который используют потоки. А ручные вызовы lock unlock заменены RAII объектом.

#include <iostream>
#include <functional>
#include <mutex>
#include <thread>
#include <vector>

void foo(int const count, ::std::reference_wrapper<::std::mutex> const mutex_ref)
{
    for (int i{}; i < count + 1; ++i)
    {
        ::std::lock_guard const lock{mutex_ref.get()};
        ::std::cout << i << '\t' << ::std::this_thread::get_id() << '\n';
    }
}

int main()
{
    ::std::mutex mutex{};
    ::std::vector<::std::jthread> thrs{};
    thrs.reserve(3);
    for (int i{}; i < 3; ++i)
    {
        thrs.emplace_back(::foo, i, ::std::reference_wrapper{mutex});
    }
    return 0;
}

online compiler

→ Ссылка