I am developing a serial port program using boost::asio.
In synchronous mode I create a thread every time read_sync function is called. All reading related operation are carried in this thread (implementation is in read_sync_impl function).
On close_port or stop_read function reading operation is stopped.
This stopped reading operation can be restarted by calling the read_sync function again.
read_sync function will never be called successively without calling close_port or stop_read function in between.
I wish to know how to implement a class wide std::jthread along with proper destructor when I call my read_sync function. In languages like Kotlin or Dart the garbage-collector takes care of this. What is C++ implementation of this.
bool SerialPort::read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
this->thread_sync_read = std::jthread(&SerialPort::read_sync_impl, this);
return true;
}
bool SerialPort::read_sync_impl(const std::stop_token& st)
{
while(true)
{
...
if (st.stop_requested())
{
PLOG_INFO << "Stop Requested. Exiting thread.";
break;
}
}
}
bool SerialPort::close_port(void)
{
this->thread_sync_read->request_stop();
this->thread_sync_read->join();
this->port.close();
return this->port.is_open();
}
class SerialPort
{
public :
std::jthread *thread_sync_read = nullptr;
...
}
Actual Code
bool SerialPort::read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
try
{
if (read_timeout not_eq ignore_read_timeout)
this->read_timeout = read_timeout;//If read_timeout is not set to ignore_read_timeout, update the read_timeout else use old read_timeout
if (this->thread_sync_read.joinable())
return false; // Thread is already running
thread_sync_read = std::jthread(&SerialPort::read_sync_impl, this);
return true;
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
return false;
}
}
void SerialPort::read_sync_impl(const std::stop_token& st)
{
try
{
while (true)
{
if (st.stop_requested())
{
PLOG_INFO << "Stop Requested in SerialPort::read_sync_impl. Exiting thread.";
break;
}
}
}
catch (const std::exception& ex)
{
PLOG_ERROR << ex.what();
}
}
class SerialPort
{
std::jthread thread_sync_read;
SerialPort() : io(), port(io), thread_sync_read()
{
read_buffer.fill(std::byte(0));
write_buffer.fill(std::byte(0));
}
}
You don't need to deal with the jthread's destructor. A thread object constructed without constructor arguments (default constructor), or one that has been joined, is in an empty state. This can act as a stand-in for your nullptr.
class SerialPort
{
public :
std::jthread thread_sync_read;
...
SerialPort(...)
: thread_sync_read() // no explicit constructor call needed, just for show
{}
SerialPort(SerialPort&&) = delete; // see side notes below
SerialPort& operator=(SerialPort&&) = delete;
~SerialPort()
{
if(thread_sync_read.joinable())
close_port();
}
bool read_sync(std::uint32_t read_length, std::int32_t read_timeout)
{
if(thread_sync_read.joinable())
return false; // already reading
/* start via lambda to work around parameter resolution
* issues when using member function pointer
*/
thread_sync_read = std::jthread(
[this](const std::stop_token& st) mutable {
return read_sync_impl(st);
}
);
return true;
}
bool close_port()
{
thread_sync_read.request_stop();
thread_sync_read.join(); // after this will be back in empty state
port.close();
return port.is_open();
}
};
Side notes
Starting and stopping threads is rather expensive. Normally you would want to keep a single worker thread alive and feed it new read/write requests via a work queue or something like that. But there is nothing wrong with using a simpler design like yours, especially when starting and stopping are rare operations
In the code above I delete the move constructor and assignment operator. The reason is that the thread captures the this pointer. Moving the SerialPort while the thread runs would lead to it accessing a dangling pointer
You're already reinitialize (move new one into) thread_sync_read in SerialPort::read_sync, everything should works.
at destructor, you need to remember delete read_sync
SerialPort::~SerialPort(){
close_port(); // if necessary to close port
delete thread_sync_read;
}
or if you declare thread_sync_read not as (raw) pointer
class SerialPort{
public:
std::jthread thread_sync_read;
}
then you don't need to delete it.
SerialPort::~SerialPort(){
close_port(); // if necessary
}
note that the destructor of std::jthread would perform necessary request_stop() and join() by itself.
Related
Consider a Connection class in a boost::asio TCP server program that looks something like this.
#ifndef CONNECTION_HPP
#define CONNECTION_HPP
#include <iostream>
#include <boost/asio.hpp>
namespace Transmission
{
class Connection
{
public:
using SocketType = boost::asio::ip::tcp::socket;
explicit Connection(boost::asio::io_service& io_service)
: m_socket{io_service},
m_outputBuffer{},
m_writeBuffer{},
m_outputStream{&m_outputBuffer},
m_writeStream{&m_writeBuffer},
m_outputStreamPointer{&m_outputStream},
m_writeStreamPointer{&m_writeStream},
m_outputBufferPointer{&m_outputBuffer},
m_writeBufferPointer{&m_writeBuffer},
m_awaitingWrite{false},
m_pendingWrites{false}
{
}
template<typename T>
void write(const T& output)
{
*m_outputStreamPointer << output;
writeToSocket();
}
template<typename T>
std::ostream& operator<<(const T& output)
{
write(output);
m_pendingWrites = true;
return *m_outputStreamPointer;
}
std::ostream& getOutputStream()
{
writeToSocket();
m_pendingWrites = true;
return *m_outputStreamPointer;
}
void start()
{
write("Connection started");
}
SocketType& socket() { return m_socket; }
private:
void writeToSocket();
SocketType m_socket;
boost::asio::streambuf m_outputBuffer;
boost::asio::streambuf m_writeBuffer;
std::ostream m_outputStream;
std::ostream m_writeStream;
std::ostream* m_outputStreamPointer;
std::ostream* m_writeStreamPointer;
boost::asio::streambuf* m_outputBufferPointer;
boost::asio::streambuf* m_writeBufferPointer;
bool m_awaitingWrite;
bool m_pendingWrites;
};
}
#endif
Where writeToSocket is defined as follows:
#include "Connection.hpp"
using namespace Transmission;
void Connection::writeToSocket()
{
// If a write is currently happening...
if(m_awaitingWrite)
{
// Alert the async_write's completion handler
// that writeToSocket was called while async_write was busy
// and that there is more to be written to the socket.
m_pendingWrites = true;
return;
}
// Otherwise, notify subsequent calls to this function that we're writing
m_awaitingWrite = true;
// Swap the buffers and stream pointers, so that subsequent writeToSockets
// go into the clear/old/unused buffer
std::swap(m_outputBufferPointer, m_writeBufferPointer);
std::swap(m_outputStreamPointer, m_writeStreamPointer);
// Kick off your async write, sending the front buffer.
async_write(m_socket, *m_writeBufferPointer, [this](boost::system::error_code error, std::size_t){
// The write has completed
m_awaitingWrite = false;
// If there was an error, report it.
if(error)
{
std::cout << "Async write returned an error." << std::endl;
}
else if(m_pendingWrites) // If there are more pending writes
{
// Write them
writeToSocket();
m_pendingWrites = false;
}
});
}
Incase it's not immediately obvious, the connection uses a double-buffering system to ensure that no buffer is both being async_writen and mutated at the same time.
The piece of code I have a question regarding is:
std::ostream& getOutputStream()
{
writeToSocket(); // Kicks off an async_write, returns immediately.
m_pendingWrites = true; // Tell async_write complete handler there's more to write
return *m_outputStreamPointer; // Return the output stream for the user to insert to.
}
such that a connection can be used like: myConnection.getOutputStream() << "Hello";
Specifically, this code relies on an assumption that async_writes completion handler will not be executed until after we return *m_outputStreamPointer. But can we safely make that assumption?
If, for instance, the async_write completion handler completes like the following, nothing would be sent to the user:
std::ostream& getOutputStream()
{
writeToSocket(); // Kicks off an async_write, returns immediately.
// Async_write's completion handler executes.
m_pendingWrites = true; // Tell async_write complete handler there's more to write
// Completion handler already executed so m_pendingWrites = true does nothing.
return *m_outputStreamPointer; // Return the output stream for the user to insert to.
}
After looking at the documentation, I found this:
Regardless of whether the asynchronous operation completes immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a manner equivalent to using boost::asio::io_service::post().
Which likely accounts for the correct behavior, but I'm not sure exactly why. Did a quick search on boost::asio::io_service::post() but that didn't add much clarity.
Thank you,
~
The documentation bit you quote merely says that the handler will not be invoked before return on the current thread, so in a single-threaded world you have your guarantee.
However if you have multiple threads running io tasks (io_context::run and friends, or implicitly using thread_pool), there is still the same race.
You can counter-act this posting all async tasks related to a connection on a strand (Strands: Use Threads Without Explicit Locking, which is an executor that serializes all tasks posted on it (see ordering guarantees in the docs).
I wanted to create a class that would represent a task that can be started running asynchronously and will run continuously (effectively in a detached thread) until a stop signal is received. The usage for the sake of this question would look like this:
auto task = std::make_shared<Task>();
task->start(); // starts the task running asynchronously
... after some time passes ...
task->stop(); // signals to stop the task
task->future.get(); // waits for task to stop running and return its result
However, a key feature of this Task class is that I cannot guarantee that the future will be waited/got... i.e. the last line may not get called before the shared pointer is destroyed.
A stripped-down toy version of the class I wrote is as follows (please ignore that everything is in public, this is just for this example's simplicity):
class MyClass : public std::enable_shared_from_this<MyClass> {
public:
~MyClass() { std::cout << "Destructor called" << std::endl; }
void start() {
future = std::async(std::launch::async, &MyClass::method, this->shared_from_this());
}
void stop() { m_stop = true; }
void method() {
std::cout << "running" << std::endl;
do {
std::this_thread::sleep_for(std::chrono::seconds(1));
} while(m_stop == false);
std::cout << "stopped" << std::endl;
return;
}
std::future<void> future;
std::atomic<bool> m_stop = false;
};
However, I discovered an undesirable feature of this code: if instead of get on the future, I just wait (e.g. if I don't care about the result of method, which in this case is a void anyway), then when task is deleted, the instance doesn't get destroyed.
I.e. doing task->future.get() gives:
running
stopped
Destructor called
But task->future.wait() gives:
running
stopped
From reading answer to What is the lifetime of the arguments of std::async? I believe the problem here is the this->shared_from_this() argument to std::async won't be destroyed until the future from the async has been made invalid (through get or destruction or otherwise). So this shared_ptr is keeping the class instance alive.
Solution Attempt 1:
Replace the line in start with:
future = std::async(std::launch::async, [this]() {
return this->shared_from_this()->method();
});
This ensures shared_ptr it creates is destroyed when the method completes, but I have been worried that there's nothing to stop this being destroyed between the time of it being captured by the lambda capture (which happens at this line, correct?) and the time the lambda is executed in the new thread. Is this a real possibility?
Solution Attempt 2:
To protect the this (task) being destroyed before the lambda function runs, I add another member variable std::shared_ptr<MyClass> myself then my start method can look like this:
myself = this->shared_from_this();
future = std::async(std::launch::async, [this]() {
auto my_ptr = std::move(this->myself);
return myself->method();
});
Here the idea is that myself will ensure that if I delete the task shared_ptr, I don't destroy the class. Then inside the lambda, the shared_ptr is transferred to the local my_ptr variable, which is destroyed on exit.
Are there issues with this solution, or have I overlooked a much cleaner way of achieving the sort functionality I'm after?
Thanks!
Solution attempt 2 I found in some scenarios would generate a deadlock exception. This appears to come from the async thread simultaneously trying to destroy the future (by destroying the instance of the class) while also trying to set the value of the future.
Solution attempt 3 - this seems to pass all my tests so far:
myself = this->shared_from_this();
std::promise<void> p;
future = p.get_future();
std::thread([this](std::promise<void>&& p) {
p.set_value_at_thread_exit( myself->method() );
myself.reset();
}, std::move(p)).detach();
The logic here is that it is safe to destroy myself (by resetting the shared pointer) once the method call is finished - its safe to delete the future of a promise before the promise has set its value. No deadlock occurs because the future is destroyed before the promise tries to transfer a value.
Any comments on this solution or potentially neater alternatives would be welcome. In particular it would be good to know if there are issues I've overlooked.
I would suggest one of the following solutions:
Solution 1, Use std::async with this instead of shared_from_this:
class MyClass /*: public std::enable_shared_from_this<MyClass> not needed here */ {
public:
~MyClass() { std::cout << "Destructor called" << std::endl; }
void start() {
future = std::async(std::launch::async, &MyClass::method, this);
}
void stop() { m_stop = true; }
void method() {
std::cout << "running" << std::endl;
do {
std::this_thread::sleep_for(std::chrono::seconds(1));
} while(m_stop == false);
std::cout << "stopped" << std::endl;
return;
}
std::atomic<bool> m_stop = false;
std::future<void> future; // IMPORTANT: future constructed last, destroyed first
};
This solution would work even if not calling wait or get on the future because the destructor of a future returned by std::async blocks until the termination of the task. It is important to construct the future last, so that it is destroyed (and thus blocks) before all other members are destroyed. If this is too risky, use solution 3 instead.
Solution 2, Use a detached thread like you did:
void start() {
std::promise<void> p;
future = p.get_future();
std::thread(
[m = this->shared_from_this()](std::promise<void>&& p) {
m->method();
p.set_value();
},
std::move(p))
.detach();
}
One drawback of this solution: If you have many instances of MyClass you will create a lot of threads maybe resulting in contention. So a better option would be to use a thread pool instead of a single thread per object.
Solution 3, Separate the executable from the task class e.g:
class ExeClass {
public:
~ExeClass() { std::cout << "Destructor of ExeClass" << std::endl; }
void method() {
std::cout << "running" << std::endl;
do {
std::this_thread::sleep_for(std::chrono::seconds(1));
} while (m_stop == false);
std::cout << "stopped" << std::endl;
return;
}
std::atomic<bool> m_stop = false;
};
class MyClass {
public:
~MyClass() { std::cout << "Destructor of MyClass" << std::endl; }
void start() {
future = std::async(std::launch::async, &ExeClass::method, exe);
}
void stop() { exe->m_stop = true; }
std::shared_ptr<ExeClass> exe = std::make_shared<ExeClass>();
std::future<void> future;
};
Like solution 1 this would block when the future is destroyed, however you don't need to take care of the order of construction and destruction. IMO this is the cleanest option.
In the following code, it is possible that event throws exception and it may be not handled in even handler, (rare but its still the case)
I want keep "lck2" unlocked while executing the event, because I don't want main thread block for "mtx2", reason is nothing more than optimization.
Can I guarantee that "lck2" is always released in catch block? or there could be runtime exceptions and therefore it may cause deadlocks or some unexpected behavior?
std::unique_lock<std::mutex>lck2(mtx2); // lock used for waiting for event.
while (_isRunning)
{
try
{
while (_isRunning)
{
// cvar2 is condition variable
cvar2.wait(lck2, [&] {return invoke; }); // wait until invoke == true
if (invoke) // if event must be invoked
{
lck2.unlock();
OnEvent(this, someproperty); // may throw exception
lck2.lock();
invoke = false; // execution completed
}
}
}
catch (...) // we need to keep this thread alive at all costs!
{
lck2.lock(); // is this safe?
invoke = false;
}
}
A rewrite of your code would probably be more appropriate, to make it easier for another developer to work on the code. I will show you two rewrites:
First, (Bad)
while (true)
{
try
{
{
std::lock_guard<std::mutex> lckx(mtx2);
if(!_isRunning)
break; //out of the main loop
}
bool should_invoke = false;
{
std::unique_lock<std::mutex> lck2(mtx2);
cvar2.wait(lck2, [&] {return invoke; });
should_invoke = invoke;
}
if (should_invoke) // if event must be invoked
{
OnEvent(this, someproperty); // may throw exception
{
std::lock_guard<std:mutex> lckx(mtx2);
invoke = false; // execution completed
}
}
}
catch (...) // we need to keep this thread alive at all costs!
{
std::lock_guard<std:mutex> lckx(mtx2);
invoke = false;
}
}
Second, (Good)
Breaking the (first) code into smaller functional units; we also note that the expression cvar2.wait(lck2, [&]{ return invoke; }) will suspend execution and only return if woken up and invoke is true, then we can infer that we only need that expression to wait. Hence we can discard the superfluous use of invoke. Hence we have:
void do_work(){
while(is_running()){
try{
wait_for_invocation();
OnEvent(this, someproperty); // may throw exception
set_invocation_state(false);
catch(...){
set_invocation_state(false);
}
}
}
Where the helpers are defined:
bool is_running(){
std::lock_guard<std::mutex> lckx(mtx2);
return _isRunning;
}
void wait_for_invocation(){
std::unique_lock<std::mutex> lck2(mtx2);
cvar2.wait(lck2, [&] {return invoke; });
}
void set_invocation_state(bool state){
std::lock_guard<std::mutex> lckx(mtx2);
invoke = state;
}
I quickly wrote some kind of wrapper to ensure some functionality in a system is always executed in a defined thread context. To make the code as small as possible, I simple use a pointer assignment to check if the thread has started.
void waitForStart() {
while (_handler == nullptr) {
msleep(100); // Sleep for 100ms;
}
msleep(100); // Sleep for 100ms to make sure the pointer is assigned
}
In my opinion, this should work in any case. Even if the assignment to _handler is for unknown reason split up into two operations on a CPU.
Is my assumtion correct? Or did I miss a case where this could go wrong?
For reference a more complete example how the system looks like. There are the System, the Thread and the Handler classes:
class Handler {
public:
void doSomeWork() {
// things are executed here.
}
};
class Thread : public ThreadFromAFramework {
public:
Thread() : _handler(nullptr) {
}
void waitForStart() {
while (_handler == nullptr) {
msleep(100); // Sleep for 100ms;
}
msleep(100); // Sleep for 100ms to make sure the pointer is assigned
}
Handler* handler() const {
return _handler;
}
protected:
virtual void run() { // This method is executed as a new thread
_handler = new Handler();
exec(); // This will go into a event loop
delete _handler;
_handler = nullptr;
}
private:
Handler *_handler;
}
class System {
public:
System() {
_thread = new Thread();
_thread->start(); // Start the thread, this will call run() in the new thread
_thread->waitForStart(); // Make sure we can access the handler.
}
void doSomeWork() {
Handler *handler = _thread->handler();
// "Magically" call doSomeWork() in the context of the thread.
}
private:
Thread *_thread;
}
You missed a case where this can go wrong. The thread might exit 5 msec after it sets the pointer. Accessing any changing variable from two threads is never reliable without synchronization.
I'd like to use boost::signals2 to handle event notification in my C++ app. I'm hoping to implement something with similar functionality to browser DOM events, specifically the ability to stop the propagation of an event so that the current receiver is the last one to know about a signal and subsequent receivers are not called. (see http://www.w3.org/TR/DOM-Level-3-Events/#events-event-type-stopImmediatePropagation for more on how this works in browsers)
I have a hypothetical App class with a signal called thingHappened. It's likely there'll only be one App instance, with several other Widget classes of varying types that will connect to thingHappened to receive ThingEvent notifications. Sometimes the widget would like to consume (stop) the ThingEvent so that no other Widgets are notified.
At first I wondered if I could achieve this with a shared_connection_block but now I understand that this only suppresses one connection at a time. Initially I passed a shared_ptr<ThingEvent> to my signal but once the signal was called there was no way to intervene with its propagation. If I pass a shared_ptr I could have signal receivers check a value on the event and return if it's set, but I don't want to push that detail off to users of my library.
The solution I've found is to pass a ThingEvent on the stack so that it is copied for each receiver. If I set mStopPropagation on the event then when it is destroyed I can throw an exception and the signal calls terminate. The downside to this is that I need my own try/catch at the point where the signal is called, and stylistically it means I'm using an exception for an unexceptional purpose. Is there a better way?
Here's my hypothetical App class, with a signal thingHappened:
class App
{
public:
boost::signals2::signal<void (class ThingEvent)> thingHappened;
};
My ThingEvent class, with some data about the event (e.g. type) and an mStopPropagation property that will cause an exception to be thrown if it is set in the destructor:
class ThingEvent
{
public:
ThingEvent(string type): mType(type), mStopPropagation(false) { }
~ThingEvent()
{
if (mStopPropagation) {
throw exception();
}
}
void stopPropagation() { mStopPropagation = true; }
string getType() { return mType; }
private:
string mType;
bool mStopPropagation;
};
Here's a sample signal consumer, a Widget, that will call stopPropagation() on an event if the type is "goat":
class Widget
{
public:
Widget(string name): mName(name) {}
~Widget() {}
void thingHappened(ThingEvent thing)
{
cout << thing.getType() << " thingHappened in widget " << mName << endl;
if (thing.getType() == "goat") {
thing.stopPropagation();
}
}
string getName()
{
return mName;
}
private:
string mName;
};
Finally, here's a quick main() function that uses these classes:
int main()
{
App app;
Widget w1("1");
Widget w2("2");
Widget w3("3");
boost::signals2::connection c1 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w1, _1));
boost::signals2::connection c2 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w2, _1));
boost::signals2::connection c3 = app.thingHappened.connect(boost::bind(&Widget::thingHappened, &w3, _1));
// all three widgets will receive this
app.thingHappened(ThingEvent("otter"));
{
// suppress calls to c2
boost::signals2::shared_connection_block block(c2,true);
// only w1 and w3 will receive this
app.thingHappened(ThingEvent("badger"));
}
// Widgets call ThingEvent::stopPropagation() if the type is "goat"
try {
// only w1 will receive this
app.thingHappened(ThingEvent("goat"));
} catch (exception &e) {
// ThingEvent's destructor throws if mStopPropagation is true
std::cout << "exception thrown by thingHappened(goat)" << std::endl;
}
return 0;
}
If you have boost to hand (I'm using 1.44) and you want to compile it, the full code and Makefile are at https://gist.github.com/1445230
You can do this with a custom signal combiner. These are explained in the "Signal Return Values (Advanced)" section of the boost.signals tutorial: http://www.boost.org/doc/libs/1_48_0/doc/html/signals/tutorial.html#id3070223
Here's the gist of it:
struct MyCombiner {
typedef bool result_type;
template <typename InputIterator> result_type operator()(InputIterator aFirstObserver, InputIterator aLastObserver) const {
result_type val = false;
for (; aFirstObserver != aLastObserver && !val; ++aFirstObserver) {
val = *aFirstObserver;
}
return val;
}
};
The input iterators to operator() refer to the collection of slots for the signal. Each time you dereference one of the iterators, it calls the slot. So you can let one of the slots return a value to indicate that it doesn't want any further slots to be called.
Then you just pass it in to the second template arg of your signal:
boost::signals2::signal<bool(ThingEvent), MyCombiner> sig;
Now you can implement thingHappened to return a bool value indicating whether or not you want the signal to be stopped.