Класс-обертка WinAPI Thread по аналогии работы std::thread

99
21 апреля 2022, 19:00

Задача: заменить std::thread немного схожим по логике (собственно написанным) классом-оберткой WinAPI Thread.
Основная проблема связана с конструктором класса Thread: он должен быть схож по логике с конструктором класса std::thread. (см. функцию main(), чтобы увидеть аналогию)
/* ??? */ означает, что я не знаю, что туда нужно написать, чтобы работало.

#include <iostream>
#include <thread>
#include <functional>
#include <stdexcept>
#include <Windows.h>
// Класс-обертка "Поток"
class Thread {
public:
    // Конструктор
    template < typename _Callable, typename..._Args >
    Thread(_Callable && callable, _Args && ...args) {
        /* ??? */
        thread_ = CreateThread(NULL, 0, /* ??? */, /* ??? */, 0, NULL);
        if (thread_ == 0) {
            throw std::system_error(errno, std::generic_category());
        }
    }
    // Деструктор
    ~Thread() {
        if (this->joinable()) {
            TerminateThread(thread_, 0);
            CloseHandle(thread_);
        }
    }
    // Отделение потока выполнения от объекта потока, позволяя продолжить выполнение независимо
    void detach() {
        if (this->joinable()) {
            if (!CloseHandle(thread_)) {
                throw std::system_error();
            }
            thread_ = INVALID_HANDLE;
        } else throw std::invalid_argument("joinable() == false!");
    }
    // Блокировка текущего потока до тех пор, пока поток, обозначенный *this, не завершит свое выполнение
    void join() {
        if (this->joinable()) {
            if (WaitForSingleObject(thread_, INFINITE) != WAIT_OBJECT_0) {
                throw std::system_error();
            }
            thread_ = INVALID_HANDLE;
        } else throw std::invalid_argument("joinable() == false!");
    }
    // Проверяет, идентифицирует ли объект std :: thread активный поток выполнения
    bool joinable() {
        return thread_ != INVALID_HANDLE;
    }
private:
    // Идентификатор дескриптора потока
    HANDLE thread_;
    // [Константа] Неверный идентификатор дескриптора потока
    static constexpr HANDLE INVALID_HANDLE = nullptr;
    // Конструктор копирования запрещен
    Thread(const Thread & ) = delete;
    // Оператор копирования запрещен
    Thread & operator = (const Thread & ) = delete;
};
// Некоторый класс SomeClass с некоторым методом someMethod,
// который нужно выполнить в отдельном потоке
class SomeClass {
public:
    SomeClass(int a, int b): a_(a), b_(b) {}
    void someMethod(int c, int d) {
        // Некоторая работа...
        std::cout << "Hello, world! " << (a_ += c) << ", " << (b_ += d) << '\n';
        Sleep(1000);
    }
private:
    int a_, b_;
};
// Точка входа
int main() {
    SomeClass some_object(1, 2);
    std::thread std_thread( & SomeClass::someMethod, some_object, 1, 1);
    Thread win_thread( & SomeClass::someMethod, some_object, 1, 1);
    std_thread.join();
    win_thread.join();
}
Answer 1

По итогу получилось следующее.

invoke.h

// from https://github.com/meganz/mingw-std-threads
#ifndef MINGW_INVOKE_H_
#define MINGW_INVOKE_H_
#include <type_traits>  //  For std::result_of, etc.
#include <utility>      //  For std::forward
#include <functional>   //  For std::reference_wrapper
namespace mingw_stdthread {
namespace detail {
//  For compatibility, implement std::invoke for C++11 and C++14
#if __cplusplus < 201703L
template<bool PMemFunc, bool PMemData>
struct Invoker {
    template<class F, class... Args>
    inline static typename std::result_of<F(Args...)>::type invoke (F&& f, Args&&... args) {
        return std::forward<F>(f)(std::forward<Args>(args)...);
    }
};
template<bool>
struct InvokerHelper;
template<>
struct InvokerHelper<false> {
    template<class T1>
    inline static auto get (T1&& t1) -> decltype(*std::forward<T1>(t1)) {
        return *std::forward<T1>(t1);
    }
    template<class T1>
    inline static auto get (const std::reference_wrapper<T1>& t1) -> decltype(t1.get()) {
        return t1.get();
    }
};
template<>
struct InvokerHelper<true> {
    template<class T1>
    inline static auto get (T1&& t1) -> decltype(std::forward<T1>(t1)) {
        return std::forward<T1>(t1);
    }
};
template<>
struct Invoker<true, false> {
    template<class T, class F, class T1, class... Args>
    inline static auto invoke (F T::* f, T1&& t1, Args&&... args) ->\
    decltype((InvokerHelper<std::is_base_of<T,typename std::decay<T1>::type>::value>::get(std::forward<T1>(t1)).*f)(std::forward<Args>(args)...)) {
        return (InvokerHelper<std::is_base_of<T,typename std::decay<T1>::type>::value>::get(std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
    }
};
template<>
struct Invoker<false, true> {
    template<class T, class F, class T1, class... Args>
    inline static auto invoke (F T::* f, T1&& t1, Args&&... args) ->\
    decltype(InvokerHelper<std::is_base_of<T,typename std::decay<T1>::type>::value>::get(t1).*f) {
        return InvokerHelper<std::is_base_of<T,typename std::decay<T1>::type>::value>::get(t1).*f;
    }
};
template<class F, class... Args>
struct InvokeResult {
    typedef Invoker<std::is_member_function_pointer<typename std::remove_reference<F>::type>::value,
            std::is_member_object_pointer<typename std::remove_reference<F>::type>::value &&
            (sizeof...(Args) == 1)> invoker;
    inline static auto invoke (F&& f, Args&&... args) -> decltype(invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...)) {
        return invoker::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    }
};
template<class F, class...Args>
auto invoke (F&& f, Args&&... args) -> decltype(InvokeResult<F, Args...>::invoke(std::forward<F>(f), std::forward<Args>(args)...)) {
    return InvokeResult<F, Args...>::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
#else
using std::invoke;
#endif
} //  Namespace "detail"
} //  Namespace "mingw_stdthread"
#endif

main.cpp

#include "invoke.h"
#include <iostream>
#include <thread>
#include <functional>
#include <stdexcept>
#include <Windows.h>
// Класс-обертка "Поток"
class Thread {
public:
    // Конструктор
    template < typename _Callable, typename..._Args >
    Thread(_Callable && callable, _Args && ...args) {
        mThreadArgument = [&callable, &args...] () {
            mingw_stdthread::detail::invoke(callable, args...);
        };
        mHandle = CreateThread(NULL, 0, run<decltype(mThreadArgument)>, &mThreadArgument, 0, NULL);
        if (mHandle == 0) {
            throw std::system_error(GetLastError(), std::generic_category());
        }
    }
    // Деструктор
    ~Thread() {
        if (this->joinable()) {
            TerminateThread(mHandle, 0);
            CloseHandle(mHandle);
        }
    }
    // Отделение потока выполнения от объекта потока, позволяя продолжить выполнение независимо
    void detach() {
        if (this->joinable()) {
            if (!CloseHandle(mHandle)) {
                throw std::system_error(GetLastError(), std::generic_category());
            }
            mHandle = INVALID_HANDLE;
        } else throw std::invalid_argument("joinable() == false!");
    }
    // Блокировка текущего потока до тех пор, пока поток, обозначенный *this, не завершит свое выполнение
    void join() {
        if (this->joinable()) {
            if (WaitForSingleObject(mHandle, INFINITE) != WAIT_OBJECT_0) {
                throw std::system_error(GetLastError(), std::generic_category());
            }
            mHandle = INVALID_HANDLE;
        } else throw std::invalid_argument("joinable() == false!");
    }
    // Проверяет, идентифицирует ли объект std :: thread активный поток выполнения
    bool joinable() {
        return mHandle != INVALID_HANDLE;
    }
private:
    // Идентификатор дескриптора потока
    HANDLE mHandle;
    // [Константа] Неверный идентификатор дескриптора потока
    static constexpr HANDLE INVALID_HANDLE = nullptr;
    // Функция-обертка для аргумента потока
    std::function<void()> mThreadArgument;
    // Функция потока
    template < class T >
    static DWORD WINAPI run(void * threadArgument) {
        (*(T*) threadArgument)();
        return 0;
    }
    // Конструктор копирования запрещен
    Thread(const Thread & ) = delete;
    // Оператор копирования запрещен
    Thread & operator = (const Thread & ) = delete;
};
// Некоторый класс SomeClass с некоторым методом someMethod,
// который нужно выполнить в отдельном потоке
class SomeClass {
public:
    SomeClass(int a, int b): a_(a), b_(b) {}
    void someMethod(int c, int d) {
        // Некоторая работа...
        std::cout << "Hello, world! " << (a_ += c) << ", " << (b_ += d) << '\n';
        Sleep(1000);
    }
private:
    int a_, b_;
};
// Точка входа
int main() {
    SomeClass someObject(1, 2);
    std::thread stdThread( & SomeClass::someMethod, someObject, 1, 1);
    Thread winThread( & SomeClass::someMethod, someObject, 1, 1);
    stdThread.join();
    winThread.join();
}
READ ALSO
В выводе расшифрованной строки присутствуют некорректные символы

В выводе расшифрованной строки присутствуют некорректные символы

сегодня я решил попробовать написать шифрование строк и у меня даже получилосьОднако в выводе расшифрованной строки присутствуют лишние...

170
Как можно переписать алгоритм сортировки слиянием, чтоб он поддерживал сортировку от большего к меньшему исходя из переданного из вне компоратора

Как можно переписать алгоритм сортировки слиянием, чтоб он поддерживал сортировку от большего к меньшему исходя из переданного из вне компоратора

Я написал алгоритм сортировки слиянием, когда я передаю стандартный компоратор от меньшего к большему, все работает нормально, но если я пытаюсь...

234
Шаблон списка c++

Шаблон списка c++

есть двусвязный список, необходимо сделать для него шаблон, чтобы можно было взаимодействовать с разными типами данных, подскажите как правильно...

78
Удаление элементов в файле

Удаление элементов в файле

Есть код, в котором генерируются последовательности и помещаются в inputtxt

178