boost::bind member function as argument inside its own member function - c++

I am following a tutorial (https://www.gamedev.net/blogs/entry/2249317-a-guide-to-getting-started-with-boostasio/) for boost asio.
Now I want to convert some of the aspects of this tutorial to a class, to learn more about what actually goes on within each part of the code. So I am trying to boost bind this:
class LDserver
{
public:
void workerThread(boost::shared_ptr<boost::asio::io_service> io_service)
{
io_service->run();
}
void createThreads()
{
this->worker_threads.create_thread(boost::bind(&LDserver::workerThread, this->io_service));
}
~LDserver() = default;
boost::thread_group worker_threads;
boost::shared_ptr<boost::asio::io_service> io_service = boost::make_shared<boost::asio::io_service>();
boost::shared_ptr<boost::asio::io_service::work> work = boost::make_shared<boost::asio::io_service::work>(*this->io_service);
boost::asio::io_service::strand strand = boost::asio::io_service::strand(*this->io_service);
};
Following the documentation, it states that this should be the correct syntax AS its own, so not as an argument. But instead I am greeted with an error message coming from the boost::bind library.
Severity Code Description Project File Line Suppression State
Error C2440 'return': cannot convert from 'R (__cdecl &)' to 'R' LockManager C:\Boost\boost_1_75_0\boost_1_75_0\boost\bind\bind.hpp 227
It work fine if I follow the documentation and put it in the mainloop, it even takes the member variable fine as an argument:
LDserver s1;
for (int i = 0; i <= 2; i++)
{
s1.worker_threads.create_thread(boost::bind(&workerThread, s1.io_service));
}
And by commenting out I am 100% sure because it doesnt take my way of syntaxing the worketThread() member function as the correct one, however after spending 2 days of trying and finding the answer, I hope someone here could enlighten me.

The problem is that the thread function isn't static, so it needs an argument for this (LDServer*). Or you can make it static:
static void workerThread(boost::shared_ptr<ba::io_service> io_service) {
io_service->run();
}
void createThreads() {
worker_threads.create_thread(
boost::bind(&LDserver::workerThread, io_service));
}
However, all the rampant dynamic allocation, shared ownership and manual threading, as well as the boost bind/shared_ptr instead of standard library are all code smells. If you're using a VeryOldOrBadBook(TM) to learn this from, please compare:
#include <boost/asio.hpp>
namespace net = boost::asio;
class LDserver : public std::enable_shared_from_this<LDserver> {
using executor_type = net::thread_pool::executor_type;
net::thread_pool _ctx{1}; // one thread please
net::strand<executor_type> _strand{_ctx.get_executor()};
public:
~LDserver() {
_ctx.join(); // don't forget to join your threads anyway
}
};

Related

Boost::beast::ssl_stream unable to deference the shared pointer, need to transform ssl_stream to websocket::stream

I am trying to write a https flex server, that can upgrade to websocket based on upgrade request. https class does the ssl handshake on std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>> m_ptls_stream
Now I need to transfer this stream to websocket class and transform it into type
std::shared_ptr<boost::beast::websocket::stream<
boost::beast::ssl_stream<boost::beast::tcp_stream>>>
But for some reason the constructor of websocket stream doesn't accept a shared pointer, and I am unable to dereference the ssl_stream shared_ptr as I get the error that the copy constructor is deleted
Severity Code Description Project File Line Suppression State
Error C2280 'boost::beast::ssl_streamboost::beast::tcp_stream::ssl_stream(const
boost::beast::ssl_streamboost::beast::tcp_stream &)': attempting to
reference a deleted
function D:\Work\remote_pc\out\build\x64-Debug\remote_pc D:\Work\boost_1_73_0\boost\asio\impl\executor.hpp 218
void async_ws_client::add_stream(std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>>&& ptls_stream)
{
if (m_ptls_context)
{
m_p_wss_stream = std::make_shared<
boost::beast::websocket::stream<
boost::beast::ssl_stream<
boost::beast::tcp_stream>>>(std::move(*ptls_stream), *m_ptls_context);
}
}
Feels like im missing something, unable to figure it out for a couple of days. Please help..!!
Also, if I do it this way
m_p_wss_stream = std::make_shared<
boost::beast::websocket::stream<
boost::beast::ssl_stream<
boost::beast::tcp_stream>>>(std::move(ptls_stream->next_layer()),
*m_ptls_context);
The socket throws error : uninitialized when I do async_accept() on the stream after creating it.
Dereferencing works. It's just that you can't construct the type you want from the arguments you pass.
Simplifying your code so it becomes readable and self-contained:
Live On Coliru
#include <boost/beast.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio.hpp>
namespace net = boost::asio;
namespace beast = boost::beast;
namespace ws = beast::websocket;
namespace ssl = net::ssl;
struct async_ws_client {
using tcp_stream = beast::tcp_stream;
using ssl_stream = beast::ssl_stream<tcp_stream>;
void add_stream(std::shared_ptr<ws::stream<tcp_stream>> ptls_stream)
{
if (m_ptls_context) {
m_p_wss_stream = std::make_shared<ws::stream<ssl_stream>>(
std::move(*ptls_stream), *m_ptls_context);
}
}
std::shared_ptr<ws::stream<tcp_stream>> m_p_tls_stream;
std::shared_ptr<ssl::context> m_ptls_context;
std::shared_ptr<ws::stream<ssl_stream>> m_p_wss_stream;
};
int main() {
}
The error novel hides the messages deep inside the shared_ptr construction forwarding machinery. However, the equivalent, much simpler code also will not compile, and for the same reason:
Live On Coliru
struct simple_async_ws_client {
using tcp_stream = beast::tcp_stream;
using ssl_stream = beast::ssl_stream<tcp_stream>;
void add_stream(ws::stream<tcp_stream>&& tls_stream) {
m_wss_stream.emplace(std::move(tls_stream), m_tls_context);
}
net::io_context m_io;
ws::stream<tcp_stream> m_tls_stream{m_io};
ssl::context m_tls_context;
std::optional<ws::stream<ssl_stream>> m_wss_stream;
};
A quick glance at your link tells me that ought to have been more like: Live On Coliru
m_wss_stream.emplace(tls_stream.next_layer().release_socket(),
m_tls_context);
Now, you can translate that back to the fully shared_ptr-overgrown version of the code:
struct async_ws_client {
using tcp_stream = beast::tcp_stream;
using ssl_stream = beast::ssl_stream<tcp_stream>;
void add_stream(std::shared_ptr<ws::stream<tcp_stream>> const& p_tls_stream)
{
if (m_p_tls_context) {
m_p_wss_stream = std::make_shared<ws::stream<ssl_stream>>(
p_tls_stream->next_layer().release_socket(), *m_p_tls_context);
}
}
std::shared_ptr<ws::stream<tcp_stream>> m_p_tls_stream;
std::shared_ptr<ssl::context> m_p_tls_context;
std::shared_ptr<ws::stream<ssl_stream>> m_p_wss_stream;
};
Note though that (ab)using shared pointers at this scale is a bit of an anti-pattern. You should probably considerunique_ptr or optional (for lazy-constructed types), or indeed enable_shared_from_this for the entire class, so all members have shared ownership by extension. This is also used in the linked documentation sample.
made a stupid mistake in understanding, cannot pass tls_context into websocket::stream constructor. The following code worked
void async_ws_client::add_stream(
std::shared_ptr<boost::beast::ssl_stream<boost::beast::tcp_stream>>&& ptls_stream)
{
if (m_ptls_context)
{
m_p_wss_stream = std::make_shared<
boost::beast::websocket::stream<
boost::beast::ssl_stream<
boost::beast::tcp_stream>>>(std::move(*ptls_stream));
}
}

std::thread constructor argument error Invalid use of non-static member function

Im writing multithreading application with thread manager contains all the threads and allows to operate them, but when im passing any arguments to constructor of std::thread, i get Error: Invalid using of non-static member function.
First thing i did was trying to pass simple void function(void), so it would be easy to do and check if it's even working. I tried passing void ClassName::function(void) and void this->function(void), but nothing works. I even tried passing reference to function in all the way i said before, but it made even more errors in the code.
Also i don't want to change any function to static, so please try to help with this without turning functions to static.
ThreadManager.cpp:
class ThreadMaster
{
static thread *m_threads[MAX_THREADS_ALLOC];
...
public:
static void addThread(thread *thrd, int *ret);
...
};
thread *ThreadMaster::m_threads[MAX_THREADS_ALLOC] = {nullptr};
mutex ThreadMaster::m_mtx;
void ThreadMaster::addThread(thread *thrd, int *ret)
{
for(int i = 0; i < MAX_THREADS_ALLOC; i++)
{
if(ThreadMaster::m_threads[i] != nullptr)
{
ThreadMaster::m_threads[i] = thrd;
if(ret != nullptr)
(*ret) = i;
}
}
}
SocketManager.cpp:
#include <thread>
using namespace std;
class SocketApplication
{
...
protected:
void check_thread(int thr, int *client );
void thr_process(int *curcli);
...
}
void SocketApplication::check_thread(int thr, int *client)
{
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
if(threadTimer.GetTime() > 2)
{
ThreadMaster::joinThread(thr);
write(m_sockmgr->GetDevice(*client)->socket, "tot", sizeof(char) * 3);
m_sockmgr->removeClient(*client);
printf("[-] some client is not responding\n");
ThreadMaster::addThread(new thread(this->thr_process, client), nullptr); //error
ThreadMaster::addThread(nullptr, nullptr); //no errors
}
}
g++ compiler (g++ ./src/main.cpp -lpthread -std=c++14 -Wno-write-strings -fpermissive -o ./build/server)
./src/net/socketManager.cpp:152:69: error: invalid use of non-static member function
ThreadMaster::addThread(new thread(this->thr_process, client), nullptr);
I expect this code to compile without any errors, so it can successful work, but as you can see it gives compile error.
new thread(this->thr_process, client)
That's not how to address a member function, plus you need to bind the this pointer so the thread knows what object to call it on.
Fortunately, thread's constructor makes this easy (recall that there is a hidden "this" first argument to member functions, which this feature simulates):
new thread(&thr_process, this, client)
Read the chapter in your book about threads for more information.
Also consider reducing your excessive use of dynamic allocation.
I'm using the boost library, and this is a cut & paste of some of my code:
boost::thread * myThread = new boost::thread(&TCPServerMaster::run, this);
Here's a non-boost thread:
subscriptionThread = new thread(std::bind(&PubNubREST::subscriptionRunner, this));
The second argument in both cases is the object to run against. In my case, I have a startThread() method, the runner is against the same object.

I cannot get an MBED ticker within a class to call a member method

I wrote the following MBED-based C++ program as an experiment for a more detailed project I am working on for my Nucleoboard Microcontroller:
#include "mbed.h"
DigitalOut greenLed(PA_5);
#include "mbed.h"
class TimedLED
{
public:
TimedLED()
{
Ticker t;
t.attach_us(this, &TimedLED::flip, 1000000);
}
void flip(void)
{
static int count = 0;
greenLed.write(count%2); //-- toggle greenLed
count++;
}
};
int main()
{
TimedLED flash;
while (1);
}
All the references I looked at seemed to indicate that t.attach_us(this, &TimedLED::flip, 1000000) should call the method, 'flip' every second and so cause the LED to toggle on and off. This is not happening, however. I cannot see what the problem is. I hope someone can help me clear this up.
I am getting the following warning message indicating that this format is deprecated, but the link to the documentation was broken, so I couldn't get more details:
Function "mbed::Ticker::attach_us(T *, M, us_timestamp_t) [with T=TimedLED, M=void(TimedLED::*)()]" (declared at /extras/mbed_fd96258d940d/drivers/Ticker.h:122) was declared "deprecated" "t.attach_us(this, &TimedLED::flip, 1000000);"
Even if it is deprecated, it still should work, shouldn't it? Also, presumably if the deprecation message is correct, there is a newer way to do the same thing. I can't find reference to an alternative method though anywhere.
You declare Ticker t; in your constructor on the stack, when the constructor exits it will clear the object, and thus the code will not run.
Declare the variable in your class, and it'll run as expected:
class TimedLED
{
public:
TimedLED()
{
t.attach(callback(this, &TimedLED::flip), 1.0f);
}
void flip(void)
{
static int count = 0;
greenLed.write(count%2); //-- toggle greenLed
count++;
}
private:
Ticker t;
};
Also note the change in the constructor, this is the prefered (non-deprecated) way to attach callbacks in mbed OS 5.

Calling a virtual function through a pointer using async in c++

I'm new to multi-threading and have limited knowledge in programming. I want to use async function in c++ to call a virtual function. Snippets of the code are given below. Any help would be much appreciated.
class Binary_Genome: public Individual
{
public:
std::string evaluate_fitness();
}
class Individual
{
public:
virtual std::string evaluate_fitness()=0;
}
int main()
{
std::string w_list;
Individual* current_ind;
//Skipped some code here
std::future<std::string> future_strs;
future_strs = std::async(current_ind->evaluate_fitness); //Complier does not understand this line.
w_list = future_strs.get();
return 0;
}
Compilation error:
error: invalid use of non-static member function
I understand std::async(current_ind->evaluate_fitness) is incorrect syntax. However, I don't know what the correct syntax is. The code works perfectly without async (w_list = current_ind->evaluate_fitness()). Thanks for the help.
Even if it were to compile, you would get memory error since Individual* current_ind; doesn't initialize the pointer. currently it points to garbage memory address.
yo ucan use pointers to objects in std::async liek that:
Object obj;
Object* pointer = &obj;
auto fut = std::async([pointer]{ return pointer->returnSomthing(); });
make sure that obj is alive as long as the async function runs. std::shared_ptr is extremly suitable for that.

Error with lib boost asio 1.47.0 in file basic_socket.hpp

i have an error in the following code when i tried to compile this:
void Server::accept(void)
{
Network::ptr connection = Network::initialize(this->my_acceptor.get_io_service());
this->my_acceptor.async_accept(connection->socket(), bind(&Server::endCmd, this, *connection, placeholders::error));
}
void Server::endCmd(Network connection, const boost::system::error_code& error)
{
if (!error)
{
std::cout << "success!" << std::endl;
connection.start();
this->accept();
}
}
VC++ 2010 tell me the following error :
Error 1 error C2248: 'boost::asio::basic_io_object<IoObjectService>::basic_io_object' : cannot access private member declared in class 'boost::asio::basic_io_object<IoObjectService>'
i know this error come to this line because when i comment it, the error disapear...
After some research, it's probably with the socket's class when i call connection->getSocket() but this function returns a ref to an instance of socket :
tcp::socket& Network::socket(void)
{
return (this->my_socket);
}
so i didn't find any solution on the web :(
Anyone have an idea plz ?
Is async_accept something you wrote yourself? If so, make sure it takes a REFERENCE to socket, and not pass by value. The error you're getting is saying that you're trying to copy construct, and the copy constructor is declared private (this is a the C++ way of enforcing that the class doesn't support copying).
I had that problem too, and i spend a few hours to see what happened. My case was:
Class A which contains a boost socket. The class A it was used as a member in class B.
class B was a pointer and it was not copyable. Member A was declared as a reference in the B class.
Original code in the B class was:
std::bind(&A::a_member, a_instance)
The problem was fixed (and of course) by using the address of the a_instance:
std::bind(&A::a_member, &a_instance).
I did not notice that, and I took me a while to resolve this. I hope that it will be help others too.