I 'm using boost beast 1.74.0. in another thread i try close the websocket but the code is broken at "acceptor.accept(socket, endpoint)" and i receive "Signal: SIG32 (Real-time event 32)" after call close.
Part from code to listen connection, What i need change to interrupt the accept correctly the service?
...
_acceptor = &acceptor;
_keepAlive = true;
while (_keepAlive) {
tcp::socket socket{ioc};
// Block until we get a connection
acceptor.accept(socket, endpoint);
// Launch the session, transferring ownership of the socket
std::thread(
&WebSocketServer::doSession,
std::move(socket),
this,
this,
getHeaderServer()
).detach();
}
close function call by another thread
void WebSocketServer::close() {
if (_acceptor != nullptr) this->close();
_keepAlive = false;
}
glibc uses SIG32 to signal the cancellation of threads created using the pthread library. Are you trying to use pthread_kill?
If not, you may be witnessing that only because you are running it under GDB. Which should be fixable by telling GDB to ignore that:
handle SIG32 nostop noprint
Finally to the original question:
there's interupption points in Boost Thread. They could help you iff you can switch to Boost Thread boost::thread instead of std::thread. Also, you have to change the thread's code to actually check for interruptions: https://www.boost.org/doc/libs/1_75_0/doc/html/thread/thread_management.html#thread.thread_management.tutorial.interruption
Since it actually sounds like you want to terminate the accept loop, why not "simply" cancel the acceptor? I'm not entirely sure this works with synchronous operations, but you could of course easily use an async accept.
Take care to synchronize access to the acceptor object itself. This means either run cancel on the same thread doing async_accept or from the same strand. By this point it surely sounds like it's easier to just do the whole thing asynchronously.
Related
I'm working on a project that uses uses a thread to connect to a server. Whenever the login button is pressed, it initialized a thread to log in with the given IP and port provided by the user.
ServerPage.h
class ServerPage {
public:
static std::thread serverThread;
static void login();
}
ServerPage.cpp
#include "ServerPage.h"
std::thread ServerPage::serverThread;
void ServerPage::login() {
while (/*server is not connected*/) {
if (/*button is clicked and thread is not running*/)
serverThread = std::thread(Client::init, ip, port);
}
}
This works well until the button is clicked more than once. I'm able to use the Client class to see the status of the server (connected, not connected, or failure) Is there a way to delete or re initialize so that it can be run until the client is connected?
First of all: threads cannot be restarted. There is no such concept in programming. Unless by "restart" you mean "kill and spawn again".
It is not possible to kill a thread in a cross-platform way. For posix (I don't know about other OS) you can use pthreads (instead of std::thread) and send kill signal to it and spawn it again. But this is a ninja way, not necessarily what you should do. For example if you kill a thread that currently holds a lock, you will end up in a deadlock. This method should be avoided. However, if you can't modify Client::init method, then there might be no other choice without weakening your requirements.
A better solution is to pass around "cancellation tokens": small objects that you can register cancel handlers on it. Then you implement Client::init to cancel itself (and do any necessary cleanup, like releasing locks) whenever cancellation is triggered. Which you trigger on click.
I wrote an asynchronous SSL socket implementation using standalone asio and am struggling to get it to reconnect after a connection reset / close by the server. I am rather new to the asio library so please bear with me.
The thread that calls io_context::run remains blocked even after a disconnect because of the steady_timer. My close() logic is responsible for resetting the socket resources and is also responsible for trying to kill the timer. This is what my code looks like right now:
Creating my async job:
timer.async_wait(std::bind(&ssl_socket::heartbeat, this));
In my close() method:
timer.expires_at(std::chrono::steady_clock::now());
timer.cancel();
According to the boost docs, cancel() should:
Cancel any asynchronous operations that are waiting on the timer.
Perhaps I misinterpreting this but I would imagine this also cancels the asynchronous job that is bound to the io_context but it doesn't. io_context::run is never released and creates a deadlock.
This is what my timer handler looks like:
void ssl_socket::heartbeat() {
spdlog::get("console")->trace("heartbeat called");
if (connected_) {
write(heartbeat_token);
spdlog::get("console")->trace("heartbeat sent");
}
timer.expires_at(std::chrono::steady_clock::now() + std::chrono::seconds(heartbeat_interval));
timer.async_wait(std::bind(&ssl_socket::heartbeat, this));
}
I would like to keep handler away from having to validate if it should renew its timer and let the close() deal with that (if possible).
You are ignoring the error code.
According to the boost docs, cancel() should:
Cancel any asynchronous operations that are waiting on the timer.
This is a bit misleading. When you read the full description for the cancel function you'll see:
This function forces the completion of any pending asynchronous wait
operations against the timer. The handler for each cancelled operation
will be invoked with the boost::asio::error::operation_aborted error
code.
Which means, your handler will be called by the cancel function, and since your handler just re-sets the expiry-time and waits again, the cycle never ends. You need to check the error code and just break out of the cycle if it is set.
if(error) return;
I am writing simple synchronous asio server.
Workflow is following - in endless cycle accept connections and create thread for each connection. I know, this is not so optimal, but async is too hard for me.
Here's my ugly code:
std::vector<asio::io_service*> ioVec;
std::vector<std::thread*> thVec;
std::vector<CWorker> workerVec;
std::vector<tcp::acceptor*> accVec;
while (true) {
ioVec.emplace_back(new asio::io_service());
accVec.emplace_back(new tcp::acceptor(*ioVec.back(), tcp::endpoint(tcp::v4(), 3228)));
tcp::socket* socket = new tcp::socket(*ioVec.back());
accVec.back()->accept(*socket);
workerVec.push_back(CWorker());
thVec.emplace_back(new std::thread(&CWorker::run, &workerVec.back(), socket));
}
The problem is first connection being done, it's correctly accepted, thread is created, and everything is good. Breakpoint is correctly triggered on "accept()" string. But if I want to create second connection (it does not matter if first is DCed or not) -> telnet is connected, but breakpoint on next string to "accept" is not triggered, and connection is not responding to anything.
All this vector stuff - I've tried to debug somehow to create separate acceptor, io_service for any connection - not helped. Could anyone point me where is error?
P.S. Visual Studio 2013
The general pattern for an asio-based listener is:
// This only happens once!
create an asio_service
create a socket into which a new connection will be accepted
call asio_service->async_accept passing
the accept socket and
a handler (function object) [ see below]
start new threads (if desired. you can use the main thread if it
has nothing else to do)
Each thread should:
call asio_service->run [or any of the variations -- run_one, poll, etc]
Unless the main thread called asio_service->run() it ends up here
"immediately" It should do something to pass the time (like read
from the console or...) If it doesn't have anything to do, it probably
should have called run() to make itself available in the asio's thread pool.
In the handler function:
Do something with the socket that is now connected.
create a new socket for the next accept
call asio_service->async_accept passing
the new accept socket and
the same handler.
Notice in particular that each accept call only accepts one connection, and you should not have more than one accept at a time listening on the same port, so you need to call async_accept again in the handler from the previous call.
Boost ASIO has some very good tutorial examples like this one
While trying to hack clean shutdown of asio app I find it quite irritating that I cant know if ios stopped because i called .stop() or because it run out of handlers.
Also when I want to kill it I cant find a way to see if it has handler in its handlers q, or even if some handlers are running atm.
So
1) Any way to see what stopped ios - .stop or running out of work (except the awful manual bIsAppShuttingDown flag )
2) Any way to see if io_service (after I called stop) is still processing something?
so I can write
ios->stop()
while(! ios.finished())
sleep(1) // :/
delete ios;
Typically the pattern is to dispatch on the io_service in a separate thread, for example:
_thread.reset(new std::thread([&]() { _service.run(); }); // so the dispatching here is in a thread
Subsequently, if you want to stop it and wait for it to finish cleanly, then the best way is:
_service.stop();
_thread->join();
This way the calling thread is blocked until the dispatch thread terminates (which happens when the call to execute the last handler (run()) completes. There is no way (AFAIK) of knowing whether the io_service ran out of work or whether stop() was called, you can certainly prevent the former by instantiating an io_service::work on the service. See the docs.
I am using boost::asio::io_service to manage some asynchronous TCP communication. That means I create a boost::asio::ip::tcp::socket and give the io_service to it. When I start the communication it goes schematically like this:
Async Resolve -> Callback -> Async Connect -> Callback -> Async Write -> Callback -> Async Read
I ommitted parts like resolve and bind. Just assume the Socket has been bound to a port and the hostname is resolved ( so connect meaning establishing the real connection to the endpoint )
Now the point is that I may start several Async Connections with the same io_service object. This means for example, that while in my io_service thread the program is about to Async Write some data, the main thread will call Async Resolve with on Socket ( but with the same io_service ).
This means that my io_service now has some parallel work to do - what I'd like to know is how it will prioritize the work?
For example it go like this
Main Thread | io_service Thread
-------------------------+-----------------------------------------------
SocketA->Async Connect |
//Some other Stuff | SocketA->Callback from Async Connect
| SocketA->Async Write
SocketB->Async Connect |
| --> ?
Now at this point I have to admit I am not quite sure how the io_service works. In the fourth line there are now two different asynchronous functions which needs to be executed.
Is io_service capable of doing the Async Connect and the Async Write simultaneously? If that is the case it is clear that always the callback from the function which is finished first will be called.
If the io_service is not capable of doing so, in which order will it do the work? If SocketA Async Write will be called first, it's callback will also be called first. Actually there will be always work until the whole operation on SocketA is finished.
EDIT :
According to ereOns comment I try to make my question a bit more precise:
From the view of the io_service thread - is the SocketA Async Connect call asynchronous or synchronous? From the view of my main thread it is of course asynchronous ( it just dispatches the command and then goes on ). But in the io_service thread will this specific Connect call block other operations?
In other words: Is one single io_service capable of Connecting to one Socket while it is reading on another?
Another example would be if I just call 2 Async Connect in my main function right after each other:
SocketA->AsyncConnect();
SocketB->AsyncConnect();
Let's say the Host from SocketA is a bit slow and it takes it two seconds to answer. So while SocketA is trying to connect would SocketB in the meanwhile also connect or would it have to wait until SocketA is done /timed out?
All the work is done in the thread where io_service.run() runs.
However, the call to any async_ method won't block this specific thread: it behaves exactly like if io_service.run() called select() on several events, and "returns" (calls a callback) whenever such an event is raised. That is, if you call:
socketA->async_connect();
socketB->async_connect();
socketB may as well connect before socketA and the associated callback would then be called first, still in the thread io_service.run() runs.
That's all the beauty of Boost Asio: it takes a very good care about polling, waiting and raising events when it is more appropriate, leaving you with the "easy" part.
You shouldn't try to predict order of execution for asynchronous operations here. async_connect just signals to io_service and returns immediately. The real work gets done in io_service object's event processing loop (io_service::run), but you don't know exact specifics. It most likely uses OS-specific asynchronous IO functions.
It's not clear what you're trying to achieve. Maybe you should use synchronous operations. Maybe you should use thread synchronization functionality.
Maybe io_service::run_one will help you (it executes at most one handler).
Maybe you'll want to call io_service::run multiple times in separate threads, creating a thread pool. That way one long completion handler won't block all the others.
boost::asio::io_service service;
const size_t ASIO_THREAD_COUNT = 3;
boost::thread_group threadGroup;
for (size_t i = 0; i < ASIO_THREAD_COUNT; ++i)
threadGroup.create_thread(boost::bind(&boost::asio::io_service::run,
&service, boost::system::error_code()));