How to make class member function as thread function using boost - c++

I am going to write an adapter class. In this class there is an xmlrpc-c server (abyss server). I want to start the server by creating a new thread, and the thread's function is the member function XMLThreadFun().
When I try to use the code below there is an error at the line of the adapter's constructor implementation:
/usr/include/boost/bind/bind.hpp:69:37: error: ‘void (Adapter::*)()’ is not a class, struct, or union type
Can anyone tell me how to solve this error, or how to achieve my goal? I really appreciate it.
Below is my code snippet:
#ifdef _MSC_VER
#pragma warning( disable : 4503 4355 4786 )
#else
#include "config.h"
#endif
#include "quickfix/FileStore.h"
#include "quickfix/SocketInitiator.h"
#include "quickfix/SessionSettings.h"
#include "Application.h"
#include <string>
#include <iostream>
#include <fstream>
#include "quickfix/SessionID.h"
#include "quickfix/Session.h"
#include "getopt-repl.h"
#include <cassert>
#include <xmlrpc-c/base.hpp>
#include <xmlrpc-c/registry.hpp>
#include <xmlrpc-c/server_abyss.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
using namespace std;
class theClient : public xmlrpc_c::method {
public:
theClient() {}
theClient(FIX::SocketInitiator* initiator) {
set<FIX::SessionID> s(initiator->getSessions());
set<FIX::SessionID>::iterator myIterator;
for (myIterator = s.begin(); myIterator != s.end(); myIterator++) {
string str(myIterator->getSenderCompID());
clientname = str;
}
}
void execute(xmlrpc_c::paramList const& paramList,
xmlrpc_c::value * const retvalP) {
*retvalP = xmlrpc_c::value_string(clientname);
}
private:
string clientname;
};
class Adapter {
private:
xmlrpc_c::registry myRegistry;
xmlrpc_c::methodPtr XMLRPCMethodP;
xmlrpc_c::serverAbyss webServer;
boost::thread webServerThread;
public:
void initWebServer(string rpcHost, string rpcPort);
void XMLThreadFun();
Adapter(string rpcHost, string rpcPort);
};
Adapter::Adapter(string rpcHost, string rpcPort) : myRegistry(), XMLRPCMethodP(new theClient), webServer(myRegistry, 8181, "/tmp/xmlrpc_log"), webServerThread(boost::bind(&Adapter::XMLThreadFun, this, &webServer))
{
initWebServer(rpcHost, rpcPort);
}
void Adapter::XMLThreadFun() {
webServer->run();
}
void Adapter::initWebServer(string rpcHost, string rpcPort) {
webServerThread.join();
}

You will need to use boost::bind to call a member function as a thread.
Something like
class MyClass {
public:
void Start();
void DoStuff( int limit );
};
MyClass foo;
boost::thread thread1( boost::bind( &MyClass::Start, &foo ) );
boost::thread thread2( boost::bind( &MyClass::DoStuff, &foo, 30 ) );
// threads do stuff here
thread1.join();
thread2.join();
Specifically here, it looks like you would change
webServerThread( boost::bind( &Adapter::XMLThreadFun, this, &webServer)
to
webServerThread( boost::bind( &Adapter::XMLThreadFun, this )

No need to use boost::bind
boost::thread thread2( boost::bind( &MyClass::DoStuff, &foo, 30 ) );
is equivalent to:
boost::thread thread2( &MyClass::DoStuff, &foo, 30 );

Related

Using class member in separate thread or äquivalent of overwriting run in C++

I am currently trying to run a class member function in a separate thread which results in a call to implicitly deleted copy constructor , there are already multiple Questions to this answered here on StackOverflow but honestly a lot of this is 5+ years old or feels hacky thats why I am asking myself what would be the best practice to do this with modern c++?
So currently I have the following :
A ZMQWorker which should run in separate threads ( sock is not Thread save)
zmqwoker.cpp
#include "zmqworker.h"
#include <QDebug>
#include <iostream>
ZMQWorker::ZMQWorker()
: sock(ctx, zmq::socket_type::dealer)
{
qDebug() << "Dealer Socket created";
}
void ZMQWorker::connectSocket()
{
std::string origin="CPP_ZMQ";
sock.connect("tcp://127.0.0.1:5555");
qDebug() << "Dealer Socket connected";
}
void ZMQWorker::receiveMessage()
{
while (1){
std::vector<zmq::message_t> recv_msg;
auto res = zmq::recv_multipart(sock,
std::back_inserter(recv_msg));
for (auto&& msg : recv_msg) {
std::cout << msg.to_string_view() << std::endl;
}
}
}
zmq::socket_t &ZMQWorker::getSock()
{
return sock;
}
zmqworker.h
#ifndef ZMQWORKER_H
#define ZMQWORKER_H
#include <zmq_addon.hpp>
#include <thread>
class ZMQWorker
{
public:
ZMQWorker();
void connectSocket();
zmq::context_t ctx;
zmq::socket_t sock;
void receiveMessage();
zmq::socket_t &getSock();
};
#endif // ZMQWORKER_H
and a ZMQBridge which should act as Bridge between QT and the ZMQ socket , since receive and send both are blocking function these should work in different Threads.
zmqbridge.h
#ifndef ZMQBRIDGE_H
#define ZMQBRIDGE_H
#include <QObject>
#include <iostream>
#include "zmqworker.h"
class ZMQBridge : public QObject
{
Q_OBJECT
public:
explicit ZMQBridge(QObject *parent = nullptr);
void createMessageSocket();
ZMQWorker sendSocket;
Q_INVOKABLE void callCoro(QString msg);
signals:
private:
void spawnWorker();
};
#endif // ZMQBRIDGE_H
zmqbridge.cpp
#include "zmqbridge.h"
#include <stdio.h>
#include <QDebug>
#include "zmq_dealer.h"
#include <iostream>
#include <msgpack.hpp>
#include <thread>
#include <chrono>
#include <iostream>
#include <string>
#include <random>
#include <nlohmann/json.hpp>
ZMQBridge::ZMQBridge(QObject *parent)
: QObject{parent},
sendSocket()
{
sendSocket.connectSocket();
}
void ZMQBridge::createMessageSocket(){}
void ZMQBridge::spawnWorker(){}
void ZMQBridge::callCoro(QString msg)
{
std::cout << "Hello from c++";
ZMQWorker receiveSocket = ZMQWorker();
std::thread (&ZMQWorker::receiveMessage, receiveSocket).detach();
qDebug() << "Hello";
nlohmann::json jmsg;
jmsg["randvar"] = "Hello";
zmq::message_t z_out(jmsg.dump());
sendSocket.getSock().send(z_out, zmq::send_flags::none);
}
Error Message:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include/c++/v1/type_traits:2596: error: call to implicitly-deleted copy constructor of 'typename decay<ZMQWorker &>::type' (aka 'ZMQWorker')
In file included from /Users/ahoehne/repos/ondoki-desktop/zmqbridge.cpp:1:
In file included from /Users/ahoehne/repos/ondoki-desktop/zmqbridge.h:4:
In file included from /Users/ahoehne/Qt/6.2.2/macos/lib/QtCore.framework/Headers/QObject:1:
In file included from /Users/ahoehne/Qt/6.2.2/macos/lib/QtCore.framework/Headers/qobject.h:46:
In file included from /Users/ahoehne/Qt/6.2.2/macos/lib/QtCore.framework/Headers/qobjectdefs.h:48:
In file included from /Users/ahoehne/Qt/6.2.2/macos/lib/QtCore.framework/Headers/qnamespace.h:44:
In file included from /Users/ahoehne/Qt/6.2.2/macos/lib/QtCore.framework/Headers/qglobal.h:45:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include/c++/v1/type_traits:2596:12: error: call to implicitly-deleted copy constructor of 'typename decay<ZMQWorker &>::type' (aka 'ZMQWorker')
return _VSTD::forward<_Tp>(__t);
^~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include/c++/v1/__config:856:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_ABI_NAMESPACE
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk/usr/include/c++/v1/thread:312:28: note: in instantiation of function template specialization 'std::__decay_copy<ZMQWorker &>' requested here
_VSTD::__decay_copy(_VSTD::forward<_Args>(__args))...));
^
/Users/ahoehne/repos/ondoki-desktop/zmqbridge.cpp:31:1: note: in instantiation of function template specialization 'std::thread::thread<void (ZMQWorker::*)(), ZMQWorker &, void>' requested here
std::thread (&ZMQWorker::receiveMessage, receiveSocket).detach();
^
/Users/ahoehne/repos/ondoki-desktop/zmqworker.h:14:20: note: copy constructor of 'ZMQWorker' is implicitly deleted because field 'ctx' has a deleted copy constructor
zmq::context_t ctx;
^
/Users/ahoehne/repos/vcpkg/installed/arm64-osx/include/zmq.hpp:903:5: note: 'context_t' has been explicitly marked deleted here
context_t(const context_t &) ZMQ_DELETED_FUNCTION;
^
In other languages like Java or Python which I am used to , I would just inherit from Thread and overwrite the run method and maybe depending on how dynamic and many I need use this with a ThreadPool combined with async/await ...How would I do this in C++ .The informations seems to be mixed and it feels like following a rabbit into it's hole to a new magic land.
Thank you for your help ....
You're passing receiveSocket by value trying to call the deleted copy constructor.
You have to either pass a pointer to your ZMQWorker:
std::thread (&ZMQWorker::receiveMessage, &receiveSocket)
or a reference:
std::thread (&ZMQWorker::receiveMessage, std::ref(receiveSocket))
But then you have to solve another problem:
ZMQWorker receiveSocket;
goes out of scope at the end of this method and will be destroyed while your other thread might still be using it.
What I did now is this :
zmqbridge.cpp
#include "zmqbridge.h"
#include <stdio.h>
#include <QDebug>
#include "zmq_dealer.h"
#include <iostream>
#include <msgpack.hpp>
#include <thread>
#include <chrono>
#include <iostream>
#include <string>
#include <random>
#include <nlohmann/json.hpp>
ZMQBridge::ZMQBridge(QObject *parent)
: QObject{parent},
sendSocket("CPP_SEND"),
receiveSocket("CPP_RECV")
{
this->sendSocket.connectSocket();
this->receiveSocket.connectSocket();
std::thread (&ZMQWorker::receiveMessage, &receiveSocket).detach();
}
void ZMQBridge::createMessageSocket(){}
void ZMQBridge::spawnWorker(){}
void ZMQBridge::callCoro(QString msg)
{
std::cout << "Hello from c++";
qDebug() << "Hello";
nlohmann::json jmsg;
jmsg["name"] = "hello";
jmsg["dispatch_to"] = "caller";
zmq::message_t z_out(jmsg.dump());
sendSocket.getSock().send(z_out, zmq::send_flags::none);
}
zmqbridge.h
#ifndef ZMQBRIDGE_H
#define ZMQBRIDGE_H
#include <QObject>
#include <iostream>
#include "zmqworker.h"
class ZMQBridge : public QObject
{
Q_OBJECT
public:
explicit ZMQBridge(QObject *parent = nullptr);
void createMessageSocket();
ZMQWorker sendSocket;
ZMQWorker receiveSocket;
Q_INVOKABLE void callCoro(QString msg);
signals:
private:
void spawnWorker();
};
#endif // ZMQBRIDGE_H
This works but it does not feel like a ideal grade solution , if so I will accept the answer provided by Stefan Riedel

Using a boost::asio::deadline_timer per thread not working

I'm newbie here, so if I have any errors just tell me.
The problem is that I have two processes and I want them to execute concurrently because they take too much time. So I thought to implement a class timer which manage its own boost::asio::io_service and create a thread for this io_service. The code is the following:
timer.hpp
#include <iostream>
#include <string>
#include <functional>
#include <thread>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
class timer
{
public:
timer(std::function<void(void)> task,
int time)
: io__(),
timer__(io__, boost::posix_time::milliseconds(time)),
repetitive_task__(task),
time_wait__(time)
{
timer__.async_wait(boost::bind(&timer::loop, this));
}
void start()
{
thread__ = std::thread([this](){
io__.run();
});
thread__.join();
}
void loop()
{
repetitive_task__();
timer__.expires_at(timer__.expires_at() + boost::posix_time::milliseconds(time_wait__));
timer__.async_wait(boost::bind(&timer::loop, this));
}
void stop()
{
timer__.cancel();
io__.stop();
}
private:
boost::asio::io_service io__;
boost::asio::deadline_timer timer__;
std::function<void(void)> repetitive_task__;
int time_wait__;
std::thread thread__;
};
For testing it, I have the simplest main I could think:
main.cpp
#include "timer.hpp"
void test1()
{
printf("action1 \n");
}
void test2()
{
printf("action 2 \n");
}
int main(int argc, char* argv[])
{
timer timer1(&test1, 100);
timer timer2(&test2, 50);
timer1.start();
timer2.start();
return 0;
}
And the result is always action1. Never action2.
I've been looking for how to implement timers properly like in this post or in this example of boost, but I still don't understand what I am doing wrong.
Thanks in advance

boost serialization: save_construct_data not called

I'm using boost to serialize object without a default constructor, however I get a weird issue : save_construct_data is not being called !
Bellow a sample program that reproduce this problem:
main.cpp
#include <vector>
#include <iostream>
#include "Test.h"
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
int main()
{
using T = float;
walid::Test<T> instance ( 2, {2.3f, -0.5f} ) ;
std::ofstream ofs ( "data" );
boost::archive::text_oarchive oa ( ofs );
oa << instance;
}
Test.h
#ifndef __Test_HEADER__
#define __Test_HEADER__
#include <list>
#include <vector>
#include <iostream>
#include <initializer_list>
namespace walid
{
template<typename T>
class Test
{
public:
std::vector<T> elements;
int in_dim ;
Test(int input_dim, std::initializer_list<T> elem)
{
in_dim = input_dim;
elements = std::vector<T>(elem);
}
void start(){};
void stop(){};
};
}
#include "Test_serialization.inl"
#endif
and finally Test_serialization.inl
namespace boost {
namespace serialization {
template<class Archive, class T>
inline void serialize(Archive & ar, walid::Test<T>& t, const unsigned int version)
{
std::cout<<"serialize Test ..."<<std::endl;
}
template<class Archive, class T>
inline void save_construct_data ( Archive & ar, const walid::Test<T>* t, const unsigned int version )
{
std::cout<<"call save_construct_data Test ..."<<std::endl;
}
template<class Archive, class T>
inline void load_construct_data ( Archive & ar, walid::Test<T>* t, const unsigned int version )
{
std::cout<<"call load_construct_data Test ..."<<std::endl;
::new ( t ) walid::Test<T> ( 2, {2.3f, -0.5f} ) ;
}
}
}
this code is supposed to print :
serialize Test ...
call save_construct_data Test ...
but it is only printing serialize Test ... (save_construct_data is not called)
Am I missing something ?
Thanks for your help.
The assumption appears to be that you are constructing walid::Test<T>.
However, if you look closely, you will realize that you don't actually construct anything.
By design Boost Serialization (de)serializes (into) lvalues. The only place where construction is required during de-serialization is when serializing dynamically allocated objects.
You can convince yourself by changing the storage of the instance to e.g. shared_ptr:
Live On Coliru
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/shared_ptr.hpp>
int main()
{
using T = float;
using Test = walid::Test<T>;
{
boost::shared_ptr<Test> shared_instance(new Test(2, {2.3f, -0.5f}));
std::ofstream ofs("data");
boost::archive::text_oarchive oa(ofs);
oa << shared_instance;
}
{
boost::shared_ptr<Test> deserialized;
std::ifstream ifs("data");
boost::archive::text_iarchive ia(ifs);
ia >> deserialized;
}
}
Prints
call save_construct_data Test ...
serialize Test ...
call load_construct_data Test ...
serialize Test ...

How to register member functions in map c++

I am trying to create a map to hold functions that can be registered and fired. I cannot seem to get the correct bind / function / pointer syntax in order to get this compiling properly.
Here is what I have: I have tried both boost::bind and boost:
#include <cstdlib>
#include <iostream>
#include <boost/bind/bind.hpp>
#include <boost/function.hpp>
#include <map>
using namespace std;
typedef const std::string& listenArg;
typedef void (*Actions)(listenArg str);
std::multimap<int, Actions> functions;
// fire in the hole!
void fire(int methods, listenArg arg0) {
std::multimap<int, Actions>::iterator function = functions.find(methods);
typedef std::pair<int, Actions> pear;
for (function = functions.begin(); function != functions.end(); ++function) {
(*(function->second))(arg0);
}
}
void listen1(listenArg arg0) {
std::cout << "listen1 called with " << arg0 << std::endl;
}
class RegisteringClass {
public:
RegisteringClass();
virtual ~RegisteringClass();
void callMeBaby(listenArg str) {
std::cout << "baby, i was called with " << str << std::endl;
}
};
int main(int argc, char** argv) {
const int key = 111;
functions.insert(make_pair<int, Actions>(key, listen1));
fire(key, "test");
// make a registeringClass
RegisteringClass reg;
// register call me baby
boost::function<void (listenArg) >
fx(boost::bind(&RegisteringClass::callMeBaby, reg, _1));
//std::bind(&RegisteringClass::callMeBaby, reg, _1);
functions.insert(
make_pair<int, Actions> (key, fx));
// fire
fire(key, "test2");
return 0;
}
Thanks for any help!
typedef boost::function < void (listenArg) > Actions;
Should be used instead of function pointer.
The problem is that you're telling the compiler that Actions is a non-member function pointer, and then you try to put a boost::function into a variable of that type. They're two totally unrelated types and such an assignment can't happen. You need to make your Actions typedef be a boost::function<void (listenArg)> instead.
you can use boost::function template
#include <cstdlib>
#include <iostream>
#include <boost/bind/bind.hpp>
#include <boost/function.hpp>
#include <map>
using namespace std;
typedef const std::string& listenArg;
typedef boost::function < void (listenArg) > Actions;
std::multimap<int, Actions> functions;

Boost thread example show error it's cannot matching function for call to 'boost::thread::thread(<unresolved overloaded function type>)'

I'm initialized thread on main function when created namspace multithread_init in order to push set_multihthread class to namespace. Why after declared boost::thread it's not matching function for call boost::thread t(smulti.thread)?
#define BOOST_THREAD_USE_LIB
#include <boost/thread.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <iostream>
#ifndef MULTITHREAD_INIT_HPP_
#define MULTITHREAD_INIT_HPP_
namespace multithread_init{
class set_multithread{
private:
//t;
public:
void thread(){
for(int i = 0; i < 5; i++){
wait(1);
std::cout<<" thread i value : "<<i<<std::endl;
}
}
void wait(int seconds)
{
boost::this_thread::sleep(boost::posix_time::seconds(seconds));
}
// void multi_case(){
// t.join();
// boost::thread t(thread);
// }
};
}
#endif /* MULTITHREAD_INIT_HPP_ */
main file follow as below.
int main()
{
/*thread */
multithread_init::set_multithread smulti;
boost::thread t(smulti.thread);
t.join();
}
You can't pass a member function that way. You need to bind it to the object
boost::thread t(boost::bind(&multithread_init::set_multithread::thread, &smulti));