I code snipped below:
#include <iostream>
#include <thread>
class Me{
public:
bool isLearning;
void operator()(bool startLearning){
isLearning = startLearning;
}
};
int main(){
Me m;
std::thread t1(m(true));
t1.join();
std::cout << m.isLearning << std::endl;
}
I can't start thread with callable object when argument is passed, is there any way to start thread and pass callable object with argument in thread constructor?
Problem #1
std::thread t1(m(true)); does not do what you think it does.
In this case you are invoking your function object and passing it's result (which is void) to the constructor of std::thread.
Solution
Try passing your function object and arguments like this:
std::thread(m, true);
Problem #2
std::thread will take a copy of your function object so the one it uses and modifies will not be the same one declared in main.
Solution
Try passing a reference to m instead by using std::ref.
std::thread(std::ref(m), true);
std::thread t1(m, true);
Bear in mind that, absent proper synchronisation,
isLearning = startLearning;
and
std::cout << m.isLearning << std::endl;
executing simultaneously constitute a data race and undefined behaviour.
Don't forget to t1.join() in the end.
Related
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);
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.
I'm using lambda's capture in order to pass parameters to boost::asio::io_context::post callback.
Is it thread safe?
Code
#include <iostream>
#include "boost/asio.hpp"
#include <thread>
int main() {
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
std::thread t([&](){
io_service.run();
});
auto var = 1;
io_service.post([&io_service, var]() {
std::cout << "v: " << var << std::endl;
io_service.stop();
});
t.join();
return 0;
}
As you can see, I pass var in the lambda's capture.
the main thread sets var's value, and thread t reads it.
I didn't use any of memory ordering, for example, std::memory_order_release after setting var to 1, and std::memory_order_acquire before reading var value. Even more, I don't think I can - because the variable var is passed by value to the lambda.
Is it safe to do that?
If not, how should it be done?
It is thread-safe.
Closure object is created by main thread (with copying var value) after var was created and initialized.
Next, closure object is passed as argument to post method which queues this function object and returns immediately without calling functor. Functor is called between post and t.join calls - post guarantees it.
So your code must be thread-safe.
You would need some synchronization method (for example, use of mutex+lock_guard)
if var was passed by reference [1] and some writing operations on var [2]
were performed between post and t.join calls:
auto var = 1;
io_service.post([&io_service, &var]() { // [1] takes by reference
std::cout << "v: " << var << std::endl; // lock mutex for printing
io_service.stop();
});
var = 10; // [2] , lock mutex for writing
// synchronization must be added because between post and t.join calls,
// reading and writing operations are executed
t.join();
in this case you would have to protect var.
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)};
// ~~~~~~~^
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.