C++11 thread wrapper function - multithreading

I'd like to have a wrapper thread function, i.e. a function executed by a thread which does some extra stuff, and then calls the user function.
template<class F, class... Args>
void wrapper(F&& user_function, Args&&... args) {
// do some extra stuff
user_function(args); // maybe I need to forward args
// do some extra stuff
}
Ok, this could be a nice wrapper, so I need a manager that uses this wrapper function and allows the user to spawn his own threads:
class ThreadManager {
public:
template<class F, class... Args>
std::thread newThread(F&& f, Args&&... args) {
return std::thread(thread_wrapper<F,Args...>, std::forward<F>(f), std::forward<Args>(args)...);
}
};
this way the thread manager SHOULD spawn a thread that uses the wrapper function which, in turn, does its extra work and calls the user function.
But the compiler now says: Attempt to use a deleted function.
The error is in the thread header:
template <class _Fp, class ..._Args, size_t ..._Indices>
inline _LIBCPP_INLINE_VISIBILITY
void
__thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>)
{
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
}
What am I missing/doing wrong?
[edit]
Using test:
void foo(int i) {
std::cout << "foo: " << i << std::endl;
}
int main(int argc, const char *argv[]) {
ThreadManager mgr;
auto t = mgr.newThread(foo, 10);
t.detach();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
return 0;
}
I'm using Xcode 7.1 with LLVM compiler, but fails on FreeBSD clang 3.3 too.
The Xcode error is:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:337:5: error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:347:5: note: in instantiation of function template specialization 'std::__1::__thread_execute' requested here
__thread_execute(*__p, _Index());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:359:42: note: in instantiation of function template specialization 'std::__1::__thread_proxy >' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());

I'm not sure what is causing the "Attempt to use a deleted function" in your example, I get other errors related to std::thread's bind mechanism.
It appears the way you are spelling out the template arguments for thread_wrapper is not playing nice with std::thread's constructor - in particular when it uses a simplified std::bind internally. The mix of perfectly forwarded function types and std::decayed function pointers seems to upset std::result_of.
we can make it work by applying some std::decay in newThread ourselves:
return std::thread( thread_wrapper<typename std::decay<F>::type,
typename std::decay<Args>::type...>,
std::forward<F>(f),
std::forward<Args>(args)... );
...but to be honest I'm not entirely sure why that works.
Alternatively, with some indirection and more forwarding, we can avoid having to spell out the template arguments.
We just need a functor that forwards to thread_wrapper (or a polymorphic lambda in C++14):
struct wrapper_helper {
template<class F, class... Args>
void operator()(F&& f, Args&&... args) const {
thread_wrapper(std::forward<F>(f), std::forward<Args>(args)...);
}
};
And use it in newThread:
return std::thread(wrapper_helper{}, std::forward<F>(f), std::forward<Args>(args)...);
Here's the full example showing arguments passed by value, reference and rvalue reference working as intended: http://coliru.stacked-crooked.com/a/b75d5a264f583237
Note: For move-only types like std::unique_ptr, you will definitely want to forward args... in thread_wrapper.

Related

C++11 Passing a function with arguments to a function running in a thread

I am in the process of writing a multithreaded TCP server. I am going to have one thread handle incoming socket connections, and spin off threads to handle the communication on those sockets. However, I want the thread handling socket connections to take as parameters a callback function with supporting parameters, and the compiler is complaining. Here is code to illustrate my problem:
template<class Function, class... Args>
void handleIncomingConnectionRequests(Function&& f, Args... args)
{
f(args...);
}
void callback(int x)
{
std::cout << x << "\n";
}
void main()
{
std::thread handleIncomingConnectionsThread(handleIncomingConnectionRequests<decltype(callback)>, callback, 5);
handleIncomingConnectionsThread.join();
}
When I attempt to compile this with clang on Windows, I get a fairly large compilation stack error, but the relevant issue seems to be the following:
error: too few arguments to function call, expected 1, have 0
f(args...);
Why does args appear to have no parameters? I'm clearly passing two arguments to the std::thread constructor. I have clearly done something wrong in the way I am passing the variables in, but I'm not sure how to resolve the issue.
EDIT: It was pointed out that I failed to define the second template argument. I have updated the code to read:
template<class Function, class... Args>
void handleIncomingConnectionRequests(Function&& f, Args... args)
{
f(args...);
}
void callback(int x)
{
std::cout << x << "\n";
}
void main()
{
std::thread handleIncomingConnectionsThread(handleIncomingConnectionRequests<decltype(callback), int>, callback, 5);
handleIncomingConnectionsThread.join();
}
I now get this error:
error: no matching function for call to 'invoke'
This error comes from the xthread file, part of the implementation of the C++ standard library for the thread include file.
Change
std::thread handleIncomingConnectionsThread(handleIncomingConnectionRequests<decltype(callback), int>, callback, 5);
to
std::thread handleIncomingConnectionsThread(handleIncomingConnectionRequests<decltype(callback)*, int>, callback, 5);
or
std::thread handleIncomingConnectionsThread(handleIncomingConnectionRequests<decltype(&callback), int>, callback, 5);

Calling a templated funtion using a thread object [duplicate]

Well I have an issue with passing data into a thread using std::thread. I thought I understood the general semantics of copy constructors, etc. but it seems I don't quite grasp the problem. I have a simple class called Log that has hidden it's copy constructor thusly:
class Log
{
public:
Log(const char filename[], const bool outputToConsole = false);
virtual ~Log(void);
//modify behavior
void appendStream(std::ostream *);
//commit a new message
void commitStatus(const std::string str);
private:
//members
std::ofstream fileStream;
std::list<std::ostream *> listOfStreams;
//disable copy constructor and assignment operator
Log(const Log &);
Log & operator=(const Log &);
}
now I have a main based heavily on http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp11/echo/blocking_tcp_echo_server.cpp
int main()
{
static int portNumber = 10000;
Log logger("ServerLog.txt", true);
logger.commitStatus("Log Test String");
try {
boost::asio::io_service ioService;
server(ioService, portNumber, logger);
}
catch (std::exception &e)
{
std::cerr << "Exception " << e.what() << std::endl;
logger.commitStatus(e.what());
}
return 0;
}
You can see that main calls the function server and passes the IOService, portNumber and logger. The logger is passed by reference, thusly:
using boost::asio::ip::tcp;
void server(boost::asio::io_service &ioService, unsigned int port, Log &logger)
{
logger.commitStatus("Server Start");
tcp::acceptor acc(ioService, tcp::endpoint(tcp::v4(), port));
while(true)
{
tcp::socket sock(ioService);
acc.accept(sock);
std::thread newThread(session, &sock, logger);
newThread.detach();
}
logger.commitStatus("Server closed");
}
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference, but I do not get the error when passing it to the session() by reference
static void session(tcp::socket *sock, Log &logger)
{
std::cout << " session () " << std::endl;
}
Now I thought that I understood correctly that a reference is the same as passing a pointer. That is, it does not call the copy constructor, it simply passes the pointer, which it lets you syntactically treat like it's not a pointer.
error C2248: 'Log::Log' : cannot access private member declared in class 'Log'
1> \log.h(55) : see declaration of 'Log::Log'
1> \log.h(28) : see declaration of 'Log'
...
: see reference to function template instantiation 'std::thread::thread(_Fn,_V0_t &&,_V1_t)' being compiled
1> with
1> [
1> Fn=void (_cdecl *)(boost::asio::ip::tcp::socket *,Log &),
1> _V0_t=boost::asio::ip::tcp::socket *,
1> _V1_t=Log &
1> ]
However if I modify it to pass a pointer, everything is happy
...
std::thread newThread(session, &sock, &logger);
...
static void session(tcp::socket *sock, Log *logger)
{
std::cout << " session () " << std::endl;
}
Why is passing by reference calling my copy constructor. Is there something special happening here because of std::thread? Did I misunderstand the copy constructor and pass by reference?
I get a different but equally baffling error if I try to use std::move() as it is done in the example. Is it possible my VS2012 is not implementing C++11 correctly?
std::thread takes its arguments by value. You can get reference semantics back by using std::reference_wrapper:
std::thread newThread(session, &sock, std::ref(logger));
Obviously you must make sure that logger outlives the thread.
I get a compiler error when I try to pass the logger (or the socket) to the thread by reference
It is not sufficient for the thread's entrypoint function to take a reference type: the thread object itself takes its arguments by value. This is because you usually want a copy of objects in a separate thread.
To get around this, you may pass std::ref(logger), which is a reference wrapper hiding reference semantics under a copyable object.

An error occur when using a thread variadic template constractor

void f(vector<int>& v){
for(const auto& x:v) cout << x;
}
class F{
private:
vector<int> v;
public:
F(vector<int>& vc):v{vc}{}
void operator()(){
for(const auto& x:v) cout << x;
}
};
int main()
{
vector<int> some_vec{3,5,77,32,1};
vector<int> vec{66,8,90,45,777};
thread t1{f,some_vec};
thread t2{F(vec)};
t1.join();
t2.join();
cout << '\n';
}
An error "no type named 'type' in 'class std::result_of< void (*(std::vector))(std::vector&)>' occur
If the argument vector in f is declared as const, void f(const vector<int>& v), the error disappears.
On the other hand, the code with function object F works just fine.
Code from Bjarne Stroustrup -- the C++ programming language 5.3.2 Passing Arguments
std::thread stores copies of the arguments passed to its constructor, and then uses rvalues of those copies as the arguments for a handler. That is, function f cannot be called with an rvalue of std::vector, as it expects a non-const lvalue reference. Even if you change it to a const lvalue reference, then it's a copy of what is actually passed to the t1's constructor.
On the contrary, class F has an implicitly defined copy-constructor, and its function call operator expects no arguments, hence you get no errors. (And F itself is constructed before it's passed to a thread's constructor).
If you want function f to operate on the some_vec instance, you'd have to wrap it with a reference wrapper:
#include <functional>
std::thread t1{f, std::ref(some_vec)};
// ~~~~~~~^

starting std::thread with anonymous class call

I am curious as to how to correctly start a std::thread using an anonymous class call.
With the below code, if my class only having 1 member variable and I call std::thread td(someclass(shared_mutex)); I get a compiler warning of warning
C4930: 'std::thread td(someclass)': prototyped function not called (was a variable definition intended?)
However, if I add a second member variable as below and call it with
std::thread td(someclass(shared_mutex,x));
I get an error with error C2064: term does not evaluate to a function taking 0 arguments.
class someclass
{
private:
std::mutex& shared_mutex;
int x;
public:
someclass(std::mutex& init_mutex, int init_x) :
shared_mutex(init_mutex),
x(init_x)
{}
//...
};
int main()
{
std::mutex shared_mutex;
int x = 10;
std::thread td(someclass(shared_mutex,x));
td.join();
return 0;
}
The only way around this is by creating an
void operator()()
{}
within the class, but is that the correct method, just to have some kind of starting function for the thread reference or am I missing some other point here? I thought the constructor would be resolver for that?
Try using { and } syntax to construct your object to avoid veximg parses as a function declaration.
std::thread td(someclass(shared_mutex,x))
becomes
std::thread td{someclass{shared_mutex,x}}
It seems that you want your thread to execute the long-running constructor of someclass and then immediately discard the newly constructed someclass. This can be done by passing the thread constructor a function object that does just that:
int main()
{
std::mutex shared_mutex;
int x = 10;
std::thread td([&]{someclass(shared_mutex,x);});
td.join();
return 0;
}
Be warned: constructing a new thread is a hugely expensive operation, so you should avoid casually spawning new threads if you have the ability to instead reuse existing threads, unless you are only going to create new threads very infrequently.

boost:thread - compiler error

I wanted to use boost::thread in my program, but get the following compiler error (Visual Studio 2005):
Error 1 **error C2064**: term does not evaluate to a function taking 0
arguments d:\...\boost_1_37_0\boost\thread\detail\thread.hpp 56
Therefore I tried to recreate the problem in a small program and modified the working Hello World example from this site.
My test code now looks like this. Why is it not working inside a class?:
#include <boost/thread.hpp>
#include <iostream>
class HelloWorld
{
public:
void hello();
void entry();
};
void HelloWorld::entry()
{
boost::thread thrd(&HelloWorld::hello);
thrd.join();
}
void HelloWorld::hello()
{
std::cout << "Hello world, I'm a thread!" << std::endl;
}
int main(int argc, char* argv[])
{
HelloWorld *bla = new HelloWorld;
bla->entry();
return 0;
}
Try it like this - the boost::thread constructor is expecting a boost::function0 (which a function pointer is, but a member function pointer isn't, due to the this pointer).
void HelloWorld::entry()
{
boost::thread thrd(boost::bind(&HelloWorld::hello,this));
thrd.join();
}
Member functions have a this pointer as the first argument. Since there is a boost::thread constructor that accepts function arguments, you don't need to use boost::bind. This will also work:
void HelloWorld::entry()
{
boost::thread thrd(&HelloWorld::hello,this);
thrd.join();
}
If your function requires arguments, you can put them after the this pointer argument.
You are passing a member function to the thread object as the function to call when the thread starts. Since the thread doesn't have the object itself, it can't call the member function. You could make the hello function static, or look at the boost::bind library to send in the object.

Resources