std::bind not able to call the class member function: C++ - c++11

I have to implement A valve Open function (for specified duration).
I am using boost::asio::deadline_timer
My class member function to open valve is:
bool Valves::valveOpen(ValveType type)
{
switch (type)
{
case eVentValve:
tblMap_.digitalInput[eVentValveK1].setBit();
if (tblMap_.digitalOutput[eOutK1VentValve].getBit())
{
isVentOpen_ = true;
}
return isVentOpen_;
case eVacuumPumpValve:
....
....
}
Class member function to close the valve is:
bool Valves::valveClose(ValveType type)
{
switch (type)
{
case eVentValve:
tblMap_.digitalInput[eVentValveK1].clearBit();
if (!tblMap_.digitalOutput[eOutK1VentValve].getBit())
{
isVentOpen_ = false;
}
return !isVentOpen_;
case eVacuumPumpValve:
....
....
}
I am trying to achieve the timer action as below
bool Valves::valveTimedOpen(ValveType type, int sec)
{
boost::asio::io_service io;
switch (type)
{
case eVentValve:
{
std::bind(&Valves::valveOpen, this, type); //Here
boost::asio::deadline_timer t(io, boost::posix_time::seconds(sec));
t.async_wait(std::bind(&Valves::valveClose, this, type));
boost::thread th(boost::bind(&boost::asio::io_service::run, &io));
return true;
}
case eVacuumPumpValve:
.....
.....
}
The code hits the line Here i.e.
std::bind(&Valves::valveOpen, this, type); but it does not go to bool Valves::valveOpen(ValveType type) function.
Can someone let me know the issue with this code?

Variables io and t go out of scope as soon as valveTimedOpen exits. You need to rethink the way you interact with the boost asio components e.g. the io_service could be a member of your class, and the timer could be dynamically allocated and needs to be deleted in the completion handler.
Also, keep in mind that if you plan on re-using an io_service object, you also need to reset it before calling run again.

auto fn = std::bind(&Test::Open, shared_from_this(), std::placeholders::_1);
fn(type);
Calls the Open() correctly.
io_service and boost::deadline_timer I have to make class member as suggested by #Ralf
Working Code:
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
class Test : public std::enable_shared_from_this <Test>
{
public:
Test() :io(), timer(io){}
void Open(int num);
void Close(int num);
void TimedOpen(int num, int dur);
void Run();
private:
boost::asio::io_service io;
boost::asio::deadline_timer timer;
};
void Test::Open(int num)
{
std::cout << "Open for Number : " << num << std::endl;
}
void Test::Close(int num)
{
std::cout << "Close for Number : " << num << std::endl;
}
void Test::TimedOpen(int num, int dur)
{
io.reset();
auto fn = std::bind(&Test::Open, shared_from_this(), std::placeholders::_1);
fn(num);
timer.expires_from_now( boost::posix_time::seconds(dur));
timer.async_wait(std::bind(&Test::Close, shared_from_this(), num));
Run();
std::cout << "Function Exiting" << std::endl;
}
void Test::Run()
{
boost::thread th(boost::bind(&boost::asio::io_service::run, &io));
}
int main()
{
auto t = std::make_shared<Test>();
t->TimedOpen(5, 5);
char line[128];
while (std::cin.getline(line, 128))
{
if (strcmp(line, "\n")) break;
}
return 0;
}

Related

boost asio io_context.run() segmentation error

I am trying to make simple server that remembers and operates some variables with receive short instructions.
I didn't complete this server, and I am trying to test connecting to the server.
But when I try to connect the server, it occurs segmentation fault.
It seems that be occured at io_context.run() function.
I don't know exact cause of this error in spite of reading asio's reference page.
Please help me..
I think that you don't have to read code of data(data.hpp).
This is server code.
//server.cpp
#include <iostream>
#include "network/sc_network.hpp"
int main(int argc, char *argv[])
{
try
{
if(argc != 2)
{
std::cerr << "Usage: server <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[1]));
server server(io_context, endpoint);
io_context.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
This is client code.
//client.cpp
#include <iostream>
#include <thread>
#include <cstdlib>
#include <boost/asio.hpp>
#include "network/data/data.hpp"
using boost::asio::ip::tcp;
class client{
private:
boost::asio::io_context& io_context_;
tcp::socket socket_;
oper_data *data_;
void do_connect(const tcp::resolver::results_type& endpoints)
{
boost::asio::async_connect(socket_, endpoints,
[this](boost::system::error_code ec, tcp::endpoint)
{
if(!ec)
{
boost::asio::async_read(socket_,
boost::asio::buffer(data_, sizeof(oper_data)),
[this](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
boost::asio::async_write(socket_,
boost::asio::buffer(data_,sizeof(oper_data)),
[this](boost::system::error_code ec, std::size_t)
{
});
}
else
{
socket_.close();
}
});
}
else
{
socket_.close();
}
});
}
public:
client(boost::asio::io_context& io_context,
const tcp::resolver::results_type& endpoints)
: io_context_(io_context),
socket_(io_context)
{
do_connect(endpoints);
}
void write(const oper_data& data)
{
boost::asio::post(io_context_,
[this, data]()
{
});
}
};
int main(int argc, char *argv[])
{
try
{
if(argc != 3)
{
std::cerr << "Usage: client <host> <port>\n";
return 1;
}
boost::asio::io_context io_context;
tcp::resolver resolver(io_context);
auto endpoints = resolver.resolve(argv[1], argv[2]);
client c(io_context, endpoints);
std::thread t([&io_context](){ io_context.run(); });
char line[128];
while (std::cin.getline(line, 128))
{
oper_data data;
//processing the line with deviding in 3 words.
}
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
this is sc_network.hpp
//sc_network.hpp
#include <boost/asio.hpp>
#include <memory>
#include <utility>
#include "data/data.hpp"
using boost::asio::ip::tcp;
class session
: public std::enable_shared_from_this<session>
{
private:
tcp::socket socket_;
data_proc data_proc_;
public:
session(tcp::socket socket)
: socket_(std::move(socket)){}
void start()
{
oper_data *input_data;
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, input_data](boost::system::error_code ec, std::size_t)
{
if(!ec)
{
data_proc_.set_data(*input_data);
data_proc_.oper_process();
start();
}
else
{
return;
}
});
}
};
class server
{
private:
tcp::acceptor acceptor_;
void do_accept()
{
acceptor_.async_accept(
[this](boost::system::error_code ec, tcp::socket socket)
{
if(!ec)
{
session ex_session(std::move(socket));
}
do_accept();
});
}
public:
server(boost::asio::io_context& io_context,
const tcp::endpoint& endpoint)
: acceptor_(io_context, endpoint)
{
do_accept();
}
};
this is data.hpp.
//data.hpp
#include <deque>
#include <cstring>
#include "favdew_utility.hpp"
#define max_oper_size 5
#define max_oper_buf max_oper_size + 1
struct oper_data {
char oper_[max_oper_buf] = "\0";
char *operand_;
char *oper_num_;
};
typedef struct oper_data oper_data;
class data_store {
private:
char *var_name_;
char *var_value_;
public:
data_store()
: var_name_(NULL), var_value_(NULL) {}
data_store(const char *var_name, const char *var_value)
{
std::size_t var_name_size = strlen(var_name) + 1;
var_name_ = new char[var_name_size];
strncpy(var_name_, var_name, strlen(var_name));
std::size_t var_value_size = strlen(var_value) + 1;
var_value_ = new char[var_value_size];
strncpy(var_value_, var_value, strlen(var_value));
}
char *var_name() { return var_name_; }
char *var_value() { return var_value_; }
void set_value(const char *var_value) {
var_value_ = new char[strlen(var_value) + 1];
strncpy(var_value_, var_value, strlen(var_value));
}
};
typedef std::deque<data_store> data_queue;
class data_proc {
private:
oper_data data_;
data_queue proc_queue;
void var()
{
if (data_store *var = this->get_var(data_.operand_)) {
var->set_value(data_.oper_num_);
}
else {
data_store input_data(data_.operand_, data_.oper_num_);
this->proc_queue.push_back(input_data);
}
}
bool sum()
{
data_store *var = this->get_var(data_.operand_);
if ( (var) && isNumber(var->var_value()))
{
const int input_data = std::atoi(var->var_value()) +
std::atoi(this->data_.oper_num_);
var->set_value(std::to_string(input_data).c_str());
return true;
}
else
return false;
}
bool dif()
{
data_store *var = this->get_var(data_.operand_);
if ((var) && isNumber(var->var_value()))
{
const int input_data = std::atoi(var->var_value()) -
std::atoi(this->data_.oper_num_);
var->set_value(std::to_string(input_data).c_str());
return true;
}
else
return false;
}
public:
data_proc()
{
oper_data input_data;
//<input_data.oper_> is already initialized with "\0"
std::memset(input_data.operand_, 0, sizeof(char *));
std::memset(input_data.oper_num_, 0, sizeof(char *));
}
data_proc(const char *oper, const char *operand, const char *oper_num)
{
strncpy(data_.oper_, oper, max_oper_size);
std::size_t operand_size = strlen(operand) + 1;
data_.operand_ = new char[operand_size];
strncpy(data_.operand_, operand, strlen(operand));
std::size_t oper_num_size = strlen(oper_num) + 1;
data_.oper_num_ = new char[oper_num_size];
strncpy(data_.oper_num_, oper_num, strlen(oper_num));
}
inline void set_data(oper_data data)
{
this->data_ = data;
}
void set_data(const char *oper, const char *operand, const char *oper_num)
{
strncpy(data_.oper_, oper, max_oper_size);
std::size_t operand_size = strlen(operand) + 1;
data_.operand_ = new char[operand_size];
strncpy(data_.operand_, operand, strlen(operand));
std::size_t oper_num_size = strlen(oper_num) + 1;
data_.oper_num_ = new char[oper_num_size];
strncpy(data_.oper_num_, oper_num, strlen(oper_num));
}
data_store *get_var(const char *var_name)
{
const std::size_t queue_size = this->proc_queue.size();
for (std::size_t i=0; i < queue_size; i++) {
if (!strcmp(this->proc_queue[i].var_name(), var_name)) {
return &proc_queue[i];
}
}
return NULL;
}
bool oper_process()
{
const char *oper = this->data_.oper_;
if (!strcmp(oper, "var")) {
var();
return true;
}
else if (!strcmp(oper, "sum")) {
sum();
return true;
}
else if (!strcmp(oper, "dif")) {
dif();
return true;
}
else {
return false;
}
}
};
this is favdew_utility.hpp
#include <string>
#include <cstdlib>
bool isNumber(const char *str)
{
std::size_t length = strlen(str);
for (std::size_t i = 0; i < length; i++)
{
if (!('0' < str[i] && str[i] < '9'))
return false;
continue;
}
return true;
}
bool isEmpty(void *buffer)
{
if (!buffer || *(char *)buffer == '\0')
return true;
else
return false;
}
There are many issues, just pointing out a few:
The declaration
session ex_session(std::move(socket));
This creates a local (stack) variable that inherits from enable_shared_from_this. Using shared_from_this will be Undefined Behaviour
Session gets immediately destructed and start() appears to be never called
If session::start() were called, it would fail because it starts an async operation without guarding the lifetime of the session instance:
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, input_data](boost::system::error_code ec, std::size_t) { ....
At the very least you need to capture the shared pointer to the session:
auto self = shared_from_this();
boost::asio::async_read(socket_,
boost::asio::buffer(input_data, sizeof(oper_data)),
[this, self, input_data](boost::system::error_code ec, std::size_t)
Even worse, input_data is never initialized. Again: Undefined Behaviour. Even if you did initialize it, you'd have to manage lifetime; why not make it a member of the session, instead of dynamically allocating (or forgetting to, as you have now)?
Caution: No, you cannot stack-allocate inside start() not even if you capture it in the lambda, because the async operations will not complete before start() exits.
Same in client: data_ is never initialized. Boom.
Even if you had it correctly allocated, using it as an asio::buffer() treats it as a POD.
Since, however, data_proc happily aggregates a data_queue which is std::deque<> it obviously IS NOT POD. More Undefined Behaviour.
What you probably need is to serialize your datastructures, instead of hoping that copying some bytes of memory is going to magically "work". It won't!
See e.g. sending/receiving a struct in boost::asio
Note While you're at is, use C++ instead of C? All the raw pointers and char* are complexity that you don't need, and it is handing your dozens of footguns or ends or rope that you're gonna hurt yourself more with.
In client.cpp you have:
std::thread t([&io_context](){ io_context.run(); });
char line[128];
while (std::cin.getline(line, 128))
{
oper_data data;
//processing the line with deviding in 3 words.
}
Soooo many things...
use std::getline, not std::istream::getline
the thread needs to be joined (https://en.cppreference.com/w/cpp/thread/thread/~thread)
if all you do is block for input, why have the thread?
io_context.run(); // replaces all of the above
data_store is also not POD, but it is also a living memory-leak. All the new-ed memory is never freed.
Note that, the way it's written, the struct might APPEAR to be POD, but logically it isn't (Rule Of Three). Basically, you wrote it in C, not C++. This foregoes all abstractions that C++ has, and now the compiler cannot tell that the struct refers to non-owned resources.
Mind you, this gives me the impression that oper_data might have similar issues (though at first I assumed that operand_ and _oper_num are supposed to point inside the fixed-size buffer oper_[])
Summarizing:
You're way ahead of yourself. Start much simpler. Use C++ (std::string, never use new/delete, actually use std::make_shared if you want to enable_shared_from_this).
You'll be much happier. Feel free to come back with simpler questions when you get stuck, ideally the SSCCE would be a (few) dozen or so lines.

What is the best way to pass callback function to std::map?

I was trying to work on the below code but the program crashes:
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef void (*callBackMethod)(string);
class CTest
{
private:
map<string, callBackMethod> mapMethod;
void testMethod(string msg)
{
cout << msg << endl;
}
public:
CTest()
{
addFunction("AA", (callBackMethod) &CTest::testMethod);
}
void addFunction(string funName, callBackMethod methodName)
{
mapMethod[funName] = methodName;
}
callBackMethod getMethod(string funName)
{
auto fun = mapMethod.find(funName);
if(fun == mapMethod.end()) { return nullptr; }
return fun->second;
}
void runFunction(string funName)
{
getMethod(funName)("test");
}
};
int main()
{
CTest test;
test.runFunction("AA");
return 0;
}
I have a requirement where I need to pass private methods to a map. The program compiles with warning:
converting from 'void (CTest::*)(std::__cxx11::string) {aka void (CTest::*)(std::__cxx11::basic_string<char>)}' to 'callBackMethod {aka void (*)(std::__cxx11::basic_string<char>)}'
and when I execute this, it crashes.
When I move the callback method outside of the class it works. My requirement is to make the program flow this was (hide the methods from external call which needs to be added to a map).
Looking forward to your comments.
If you need to point to both CTest member functions and free functions, then you can use std::function<void(std::string)>.
#include <iostream>
#include <string>
#include <map>
#include <functional>
using namespace std;
using callBackFunction = std::function<void(string)>;
void testFunction(string msg)
{
cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
}
class CTest
{
private:
map<string, callBackFunction> mapMethod;
void testMethod(string msg)
{
cout << "[" << __PRETTY_FUNCTION__ << "] " << msg << endl;
}
public:
CTest()
{
addFreeFunction("AA", testFunction);
addMemberFunction("BB", &CTest::testMethod);
}
void addMemberFunction(string funName, void(CTest::*methodName)(string))
{
using std::placeholders::_1;
mapMethod[funName] = std::bind(methodName, this, _1);
}
void addFreeFunction(string funName, void(*methodName)(string))
{
mapMethod[funName] = methodName;
}
callBackFunction getMethod(string funName)
{
auto fun = mapMethod.find(funName);
if(fun == mapMethod.end()) { return nullptr; }
return fun->second;
}
void runFunction(string funName)
{
getMethod(funName)("test");
}
};
int main()
{
CTest test;
test.runFunction("AA");
test.runFunction("BB");
return 0;
}
Notice that CTest must insert elements into the map in a different way depending on what type of function you are passing, since for member functions you must provide the object for which it is to be invoked, this in this example. This is achived by using std::bind.
Since you want to use member variables you need to specify the signature differently in your typedef:
In C++ Builder the following can be done:
typedef void(__closure *callBackMethod)(string);
If you do that, I do suggest that you keep a smart pointer to the object that the member belongs to so that you can check if the object is still valid before calling the function otherwise it will crash the application.
The __closure keyword is a C++ Builder extension to work around the requirement to use fully qualified member names source
To handle both global and member functions we have the following:
typedef void(__closure *callBackMethodMember)(string);
typedef void (*callBackMethodGlobal)(string);
/* And then on 2 overloaded functions */
void addFunction(string funName, callBackMethodMember methodName) {}
void addFunction(string funName, callBackMethodGlobal methodName) {}

How to initialize constant string for multiple tests in google test?

I'm using google test and I have a cpp-file containing several tests. I would like to initialize a string with the current date and time when starting the first test. I would like to use this string in all other tests, too. How can I do this.
I've tried the following (m_string being a protected member of CnFirstTest), but it didn't work (since the constructor and SetUp will be called before each test):
CnFirstTest::CnFirstTest(void) {
m_string = currentDateTime();
}
void CnFirstTest::SetUp() {
}
TEST_F(CnFirstTest, Test1) {
// use m_string
}
TEST_F(CnFirstTest, Test2) {
// use m_string, too
}
You can use a gtest testing::Environment to achieve this:
#include <chrono>
#include <iostream>
#include "gtest/gtest.h"
std::string currentDateTime() {
return std::to_string(std::chrono::steady_clock::now().time_since_epoch().count());
}
class TestEnvironment : public ::testing::Environment {
public:
// Assume there's only going to be a single instance of this class, so we can just
// hold the timestamp as a const static local variable and expose it through a
// static member function
static std::string getStartTime() {
static const std::string timestamp = currentDateTime();
return timestamp;
}
// Initialise the timestamp.
virtual void SetUp() { getStartTime(); }
};
class CnFirstTest : public ::testing::Test {
protected:
virtual void SetUp() { m_string = currentDateTime(); }
std::string m_string;
};
TEST_F(CnFirstTest, Test1) {
std::cout << TestEnvironment::getStartTime() << std::endl;
std::cout << m_string << std::endl;
}
TEST_F(CnFirstTest, Test2) {
std::cout << TestEnvironment::getStartTime() << std::endl;
std::cout << m_string << std::endl;
}
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
// gtest takes ownership of the TestEnvironment ptr - we don't delete it.
::testing::AddGlobalTestEnvironment(new TestEnvironment);
return RUN_ALL_TESTS();
}

What is the return type of this auto?

With some code left out, elsewhere on SOF there is code that looks like this:
// CRTP Abstract Base class for implementing static subject.
// Example Subclass Usage -- Printing Observer:
class Printer : public Observer<Printer> {
public:
Printer() : timesTriggered_(0) {}
template <typename... Args>
void OnNotify(Pressure<Args...> &subject, EventType event) {
std::cout << "Observer ID: " << this->GetID() << std::endl;
switch (event) {
case EventType::UNKNOWN: {
std::cout << "Unknown Event -- Event #" << timesTriggered_++
<< std::endl;
std::cout << "Pressure: " << subject.GetPressure() << std::endl;
break;
}
default: { break; }
}
}
private:
int timesTriggered_;
};
// CRTP Abstract Base class for implementing static subject.
// Example Subclass Usage -- Pressure Sensor:
template <typename... Obs>
class Pressure : public Subject<Pressure<Obs...>, Obs...> {
public:
typedef Subject<Pressure<Obs...>, Obs...> BaseType;
Pressure(std::tuple<Obs &...> &&observers, int pressure)
: BaseType(std::move(observers)), pressure_(pressure) {}
void Change(int value) {
pressure_ = value;
this->NotifyAll(EventType::UNKNOWN);
}
int GetPressure() const { return pressure_; }
private:
int pressure_;
};
// Binding function for use with MakeSubject
// Arguments: observer objects to observe subject notifications
// Return: tuple of references to observers
template <typename... Obs> std::tuple<Obs &...> BindObservers(Obs &... obs) {
return std::tuple<Obs &...>(obs...);
}
// Creator to ease subject creation
// Template Arguments: Subject subclass type
// Arguments: Result from BindObservers
// Any constructor arguments for Subject subclass
// Return: Subject subclass
// Example Usage:
// auto pressure = MakeSubject<Pressure>(BindObservers(printerObs), initialPressure);
template <template <typename...> class T, typename... Args, typename... Obs>
T<Obs...> MakeSubject(std::tuple<Obs &...> &&obs, Args &&... args) {
return T<Obs...>(std::move(obs), args...);
}
In main.cpp
int main() {
Printer printerObs1;
Printer printerObs2;
const int initialPressure = 1;
auto pressure = MakeSubject<Pressure>(
BindObservers(printerObs1, printerObs2), initialPressure);
pressure.Change(12);
}
I need to break out the BindObservers and the return type of MakeSubject, but I can't correctly figure out what to replace both **auto in the pseudo-code below:**
auto obs = BindObservers(printerObs1, printerObs2);
auto pressure = MakeSubject<Pressure>(obs, initialPressure);
What is the exapanded version return types of both auto above? I need to store the return values in std::vector and AFAIK, I can't say
std::vector<auto> vec
[Although I don't see why not since the compiler can probably figure it out]
You can use std::vector<decltype(pressure)>.
But the type should be Pressure<Printer, Printer>.

boost::asio doesn't work

With the following class
the header:
namespace msgSrv {
class endPoint {
public:
asio::ip::udp::endpoint ep;
endPoint(std::string ip, int port);
};
class msgSrv {
private:
asio::ip::udp::socket *asioSocket;
asio::io_service *asioIoService;
int listenPort;
boost::array<char, 1> rcvBuff;
asio::ip::udp::endpoint lastRcvdPcktEndp;
char * sbuff;
public:
boost::condition_variable cond;
boost::mutex mut;
msgSrv(int listenPort);
virtual ~msgSrv();
void start();
void pckRcvd(const asio::error_code& error, std::size_t bytes_transferred);
void sendTo(const char* buff, int len, endPoint ep);
void sendHnd(const asio::error_code& error, std::size_t bytes_transferred);
};
}
the .cpp
#include "msgSrv.h"
namespace msgSrv {
endPoint::endPoint(const std::string ip, int port) {
asio::ip::address addr = asio::ip::address::from_string(ip);
ep = asio::ip::udp::endpoint(addr, port);
}
msgSrv::msgSrv(int listenPort) {
// TODO Auto-generated constructor stub
this->listenPort = listenPort;
try {
asioIoService = new asio::io_service();
asioSocket = new asio::ip::udp::socket(*asioIoService,
asio::ip::udp::endpoint(asio::ip::udp::v4(), listenPort)); //new asio::ip::udp::socket_(*asioIoService, udp::endpoint(udp::v4(), listenPort));
} catch (std::exception &e) {
std::cerr << "Error initializing ioservice or socket:" << e.what();
}
asioIoService->run();
}
msgSrv::~msgSrv() {
// TODO Auto-generated destructor stub
delete asioIoService;
delete asioSocket;
}
void msgSrv::start() {
asioSocket->async_receive_from(asio::buffer(rcvBuff), lastRcvdPcktEndp,
boost::bind(&msgSrv::pckRcvd, this, asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
void msgSrv::pckRcvd(const asio::error_code& error,
std::size_t bytes_transferred) {
std::cout << "Rcvd! " << lastRcvdPcktEndp.address().to_string() << ":"
<< lastRcvdPcktEndp.port() << "\n";
}
void msgSrv::sendTo(const char* buff, int len, endPoint ep) {
sbuff = new char[len];
mempcpy(sbuff, buff, len);
asioSocket->async_send_to(asio::buffer(sbuff, len), ep.ep, boost::bind(
&msgSrv::sendHnd, this, asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
void msgSrv::sendHnd(const asio::error_code& error,
std::size_t bytes_transferred) {
std::cout << "Snt!\n";
delete sbuff;
}
}
and the following "main" file:
int main()
{
msgSrv::msgSrv aa(4450);
aa.start();
msgSrv::endPoint ep("127.0.0.1", 4450);
std::string a("Prova!");
int len = a.length();
aa.sendTo(a.c_str(), len, ep);
std::cout << "sent...\n";
std::cout << "notified...\n";
}
all I get is:
terminate called after throwing an instance of 'asio::system_error'
what(): mutex: Invalid argument
sent...
notified...
What's wrong?? I tried even to put a while(1) in the main, to see if something happens... I even tried to put a condition in the main that is unlocked by the receive handler... all remains locked... So what??? No idea!
I don't see you actually locking any muxtex, so that error is strange.
However your problem is to calling asioIoService->run() inside the constructor, witch fall in infinite loop. The solution is to create a new boost::thread, witch call asioIoService->run() itself. This thread will be processing all jobs. You may also call asio::io_service::run() with more then one thread, to get processing on more then one job at the same time.
m_thread = new boost::thread(boost::bind(&asio::io_service::run,asioIoService));
Calling asioIoService->stop() will force exit of asio::io_service::run(), thus closing the thread. You must join this thread to ensure that thread terminates before destroying asioIoService pointer in the destructor of your msgSrv class.

Resources