2016-04-07 177 views
0

所以我有一个具有我想要线程的成员函数的对象。由于这个功能将被操纵的一些资源的对象外,我要通过引用传递互斥作为参数传递给该函数:将std :: mutex作为参数的成员函数的线程化

#include <iostream> 
#include <mutex> 
#include <thread> 

class foo 
{ 
    public: 
     void bar(std::mutex &m) 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Threading this function works!" << std::endl; 
     } 
}; 


int main() 
{ 
    foo a; 
    std::mutex m; 
    std::thread bar_thread(&foo::bar, std::ref(a), std::ref(m)); 
    bar_thread.join(); 
    return 0; 
} 

此编译和运行在Visual Studio 2013/VC++细。但是,当我尝试在g ++中编译时失败。该错误消息也很神秘,这使得它很难理解什么编译器抱怨:

/usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’: 
/usr/include/c++/4.8/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (foo::*)(std::mutex&); _Args = {std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>}]’ 
thread_test.cpp:63:69: required from here 
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’ 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
                  ^
/usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<std::_Mem_fn<void (foo::*)(std::mutex&)>(std::reference_wrapper<foo>, std::reference_wrapper<std::mutex>)>’ 
     _M_invoke(_Index_tuple<_Indices...>) 
     ^

我有这事做性病的非复制性::互斥体,也许是怀疑g ++中的std :: ref实现与vC++中的不同?这只是一个随机猜测。

任何熟悉两种不同C++编译器精妙之处的人都知道是什么导致了这个问题,以及它如何解决?

+1

版本的gcc? –

+0

@RichardHodges g ++ 4.8.4 –

回答

1

传递一个reference_wrapper作为INVOKE的'this'参数,其中f是一个成员函数指针,它的标准为C++ 17。

在此之前,它不是严格有效的。

替代:

#include <mutex> 

#include <thread> 
#include <iostream> 

class foo 
{ 
    public: 
     void bar(std::mutex &m) 
     { 
      std::lock_guard<std::mutex> lock(m); 
      std::cout << "Threading this function works!" << std::endl; 
     } 
}; 


int main() 
{ 
    foo a; 
    std::mutex m; 
    std::thread bar_thread(&foo::bar, std::addressof(a), std::ref(m)); 
    bar_thread.join(); 
    return 0; 
} 

推理:

std::thread::thread<>(f, args...)在INVOKE方面实现(F,ARGS ...)

一些参考资料这里:

http://en.cppreference.com/w/cpp/concept/Callable

+0

这似乎工作,谢谢! –

+1

@发大块它保证按标准工作! –

+0

还有一件事,当函数没有将互斥体作为参数时,如何使用std :: ref()工作?或者只有在函数需要参数时才按照INVOKE实现? –

0

当一个指向对象被传递,而不是参考(包装)该编译以g ++:

std::thread bar_thread(&foo::bar, &a, std::ref(m)); 

显然,由Richard霍奇作为回答,引用包装不支持作为被叫直到C++ 17。

+0

它不是一个错误,除非它不适用于-std = C++ 17 –

+0

@RichardHodges我不熟悉标准的那部分内容,但是我把它和cppreference的单词当作了它。 – user2079303

+1

我认为这比历史上的事情更多是历史事故。只是在以前的标准中没有提到想象中的INVOKE函数的arg2引用包装(可能是因为没有人认为他们需要它)。 std :: invoke()作为C++ 17的函数而存在。结果是整容了。 –

相关问题