c++ - 指向成员对象的指针 - 中断线程

标签 c++ multithreading

这是 a question I got answered yesterday 的跟进.

我正在尝试为成员函数创建一个中断线程,但我不知道这些错误是什么:

[vagrant@localhost projects]$ g++ -o test test.cpp -lpthread
test.cpp: In instantiation of ‘InterruptibleThread::InterruptibleThread(Function&&, Args&& ...)::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, Args&& ...)> [with auto:1 = void (MyClass::*)(int); Function = void (MyClass::*)(int); Args = {MyClass*, int}; std::atomic_bool = std::atomic<bool>]’:
/usr/local/include/c++/6.3.0/type_traits:2481:26:   required by substitution of ‘template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, MyClass*&&, int&&)>; _Args = {std::reference_wrapper<std::atomic<bool> >, std::reference_wrapper<std::atomic<bool> >, void (MyClass::*)(int), MyClass*, int}]’
/usr/local/include/c++/6.3.0/type_traits:2492:55:   required from ‘struct std::__result_of_impl<false, false, InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, MyClass*&&, int&&)>, std::reference_wrapper<std::atomic<bool> >, std::reference_wrapper<std::atomic<bool> >, void (MyClass::*)(int), MyClass*, int>’
/usr/local/include/c++/6.3.0/type_traits:2496:12:   required from ‘class std::result_of<InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, MyClass*&&, int&&)>(std::reference_wrapper<std::atomic<bool> >, std::reference_wrapper<std::atomic<bool> >, void (MyClass::*)(int), MyClass*, int)>’
/usr/local/include/c++/6.3.0/functional:1365:61:   required from ‘struct std::_Bind_simple<InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, MyClass*&&, int&&)>(std::reference_wrapper<std::atomic<bool> >, std::reference_wrapper<std::atomic<bool> >, void (MyClass::*)(int), MyClass*, int)>’
/usr/local/include/c++/6.3.0/thread:137:26:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]::<lambda(std::atomic_bool&, std::atomic_bool&, auto:1&&, MyClass*&&, int&&)>; _Args = {std::reference_wrapper<std::atomic<bool> >, std::reference_wrapper<std::atomic<bool> >, void (MyClass::*)(int), MyClass*, int}]’
test.cpp:41:33:   required from ‘InterruptibleThread::InterruptibleThread(Function&&, Args&& ...) [with Function = void (MyClass::*)(int); Args = {MyClass*, int}]’
test.cpp:111:53:   required from here
test.cpp:36:9: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘fxn (...)’, e.g. ‘(... ->* fxn) (...)’
      fxn( forward< Args >( args )... );

当前代码:

using namespace std;

class InterruptThreadException {};

class InterruptibleThread {
private:
    static thread_local atomic_bool* stopRef;
    static thread_local atomic_bool* pauseRef;
    atomic_bool stopFlag{false};
    atomic_bool pauseFlag{false};
    thread thrd;

public:
    friend void checkForInterrupt( );
    template < typename Function, typename... Args >
    InterruptibleThread( Function&& _fxn, Args&&... _args )
        : thrd(
                []( atomic_bool& sr, atomic_bool& pr, auto&& fxn, Args&&... args ) {
                    stopRef = &sr;
                    pauseRef = &pr;
                    fxn( forward< Args >( args )... );
                },
                ref( stopFlag ),
                ref( pauseFlag ),
                forward< Function >( _fxn ),
                forward< Args >( _args )... ) {
        thrd.detach( );
    }
    bool stopping( ) const {
        return stopFlag.load( );
    }

    void stop( ) {
        stopFlag.store( true );
    }

    void pause( ) {
        pauseFlag.store( true );
        cout << "setting pause flag: " << pauseFlag.load( ) << endl;
    }

    void start( ) {
        pauseFlag.store( false );
    }
};

void checkForInterrupt( ) {
    cout << "Pause flag: " << InterruptibleThread::pauseRef->load( ) << endl;
    cout << "Stop flag: " << InterruptibleThread::stopRef->load( ) << endl;
    while ( InterruptibleThread::pauseRef->load( ) ) {
        cout << "Paused\n";
        this_thread::sleep_for( chrono::seconds( 1 ) );
    }
    if ( !InterruptibleThread::stopRef->load( ) ) {
        return;
    }
    throw InterruptThreadException( );
}

thread_local atomic_bool* InterruptibleThread::stopRef = nullptr;
thread_local atomic_bool* InterruptibleThread::pauseRef = nullptr;

void doWork( ) {
    int i = 0;
    try {
        while ( true ) {
            cout << "Checking for interrupt: " << i++ << endl;
            checkForInterrupt( );
            this_thread::sleep_for( chrono::seconds( 1 ) );
        }
    } catch ( InterruptThreadException ) {
        cout << "Interrupted\n\n";
    }
}

class MyClass {
private:
    int myInt;
    void setInt( int i ) {
        myInt = i;
    }

public:
    MyClass( ) : myInt( 1 ) {
    }
    void myWork( int i );
    void doWork( );
};

void MyClass::myWork( int i ) {
    setInt( i );
    cout << "myInt value: " << myInt << endl;
}

void MyClass::doWork( ) {
    InterruptibleThread t( &MyClass::myWork, this, 666 );
}

int main( ) {
    MyClass mc;
    mc.doWork( );

    cout << "Press enter to exit" << endl;
    getchar( );
    return 0;
}

我尝试了编译器的建议,然后得到了一个与折叠表达式相关的错误(afaik 是 C++17,我不会使用超过 14 的任何东西)。知道如何让它发挥作用吗?

我有一个不使用 lambda 的工作版本,但我真的很好奇如何让它与原始代码一起工作。

最佳答案

指向成员函数的指针与指向非成员函数或其他仿函数的指针使用不同的语法进行调用。自 Function在你的情况下是 void (MyClass::*)(int) ,您需要使用语法 (object.*fxn)(arg) 来调用它或 (objectPtr->*fxn)(arg) .

如果您可以访问 C++17 功能,则可以使用 std::invoke统一调用不同类型的可调用对象:

InterruptibleThread( Function&& _fxn, Args&&... _args )
    : thrd(
            []( atomic_bool& sr, atomic_bool& pr, auto&& fxn, auto&&... args ) {
                stopRef = &sr;
                pauseRef = &pr;
                std::invoke(std::move(fxn), std::move(args)...);
            },
            //...

注意:我改了Args&&... argsauto&&... argsArgs&&...可能会导致问题。

如果您无法访问 C++17,您可以实现 invoke你自己很容易:

template <typename Callable,
          typename... Args,
          typename = std::enable_if_t<!std::is_member_function_pointer<Callable>::value>>
decltype(auto) invoke(Callable&& c, Args&&... args) {
    return std::forward<Callable>(c)(std::forward<Args>(args)...);
}

template <typename T,
          typename T2,
          typename Ret,
          typename... FuncArgs,
          typename... Args,
          typename = std::enable_if_t<!std::is_pointer<T2>::value>>
decltype(auto) invoke(Ret (T::*c)(FuncArgs...), T2&& t, Args&&... args) {
    return (std::forward<T>(t).*c)(std::forward<Args>(args)...);
}

template <typename T,
          typename T2,
          typename Ret,
          typename... FuncArgs,
          typename... Args>
decltype(auto) invoke(Ret (T::*c)(FuncArgs...), T2* t, Args&&... args) {
    return (t->*c)(std::forward<Args>(args)...);
}

这并没有做 std::invoke 的所有事情可以,但它可以满足您的所有需求。

关于c++ - 指向成员对象的指针 - 中断线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45619466/

相关文章:

c++ - 如何避免许多 #ifdef 用于记录语句

c++ - 返回后字符变化

c++ - gcc编译错误 cv.h not found for Opencv

c++ - 关于 delete() 类实例及其静态方法/变量的问题

c# - 处理 BackGroundWorker 的正确方法

c# - 在启动线程之前无法更改 WPF 控件状态

c++ - 未执行代码的性能

java - 对 getClass 的 jni 调用为作业对象返回 null

multithreading - 如何在保持纵横比的同时在 hls 输出上使用刻录文本构建 ffmpeg

Java让 hibernate 线程在线程池中工作