Any way to cancel signal propagation in boost signals2 without exceptions? - c++

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.

Related

Create new instance of std::thread/std::jthread on every read call

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.

Call a method immediately after another one finished

I have the following pseudocode as part of a C++ project:
class BasicSender
{
public:
virtual void confirmation(int id) = 0;
int sendMessage(string x)
{
Message x = createMessageFromString(x);
if(! canSendMessage(m))
{
MessageStore::storeMessageForLater(this, m); // just store it
}
// *** HERE ***
return m.messageId;
}
};
void threadFunction()
{
while(1)
{
while(MessageStore::hasMessagesToBeSent())
{
StoredMessage m = MessageStore.getNextUnsentMessage();
if(m.basicSender.sendStoredMessage(m.message))
{
m.confirmation(m.message.messageId);
}
}
}
}
and the usage of it:
class ConcreteSender : public BasicSender
{
virtual void confirmation(int id)
{
cout << "Yippe " << id << " is sent";
}
};
int main() {
ConcreteSender a;
int ID = a.sendMessage("test");
... other stuff
}
And what I try to achieve:
is it even remotely possible to call the confirmation for succesfully delivered messages method right after sendMessage finished (ie: it returned to the caller and the caller (in main) has the ID value). If I put the method call at the place *** HERE *** the virtual method will get called before sendMessage finished and the user will be confused that the received a confirmation for a message ID he had no clue about. Yes, I have methods which can check if a message was sent or not, and yes, I can create a thread which from time to time pulls the MessageStore to see if the message was delivered or not. But I am more specifically interested if it is possible to somehow chain in the two function calls, in case of success: confirmation called right after sendMessage returns. If yes, how? (Please note, I cannot modify the signature of the functions, third party library :( )
If you want the ID of the new message in the scope of main, but you want it to indicate the ID of a message that has actually been sent, then you can use a promise/future pair. The ID will be available in main as soon as sendMessage returns, but attempting to read its value will block the main thread until the worker thread has finished actually sending that message.
This will involve changing Message to contain a promise, and changing sendMessage to return a future that references that promise.
class Message
{
public:
/*...*/
std::promise<int> messageIdOnceSent;
private:
/* ...*/
int messageId;
};
class BasicSender
{
public:
virtual void confirmation(int id) = 0;
std::future<int> sendMessage(string x)
{
Message x = createMessageFromString(x);
if(! canSendMessage(m))
{
MessageStore::storeMessageForLater(this, m); // just store it
}
// !!
return std::future<int>(x.messageIdOnceSent);
}
};
void threadFunction()
{
while(1)
{
while(MessageStore::hasMessagesToBeSent())
{
StoredMessage m = MessageStore.getNextUnsentMessage();
if(m.basicSender.sendStoredMessage(m.message))
{
m.confirmation(m.message.messageId);
// !!
m.message.messageIdOnceSent.set_value(m.message.messageId);
}
}
}
}
int main() {
ConcreteSender a;
std::future<int> ID = a.sendMessage("test");
// !!
std::cout << ID.get() << '\n'; // blocks until message has actually been sent
}
This is the closest solution I can get if you really want the ID "immediately after" sendMessage returns but not before the message has actually been sent.
Generally you don't want to block your main thread, but if your main function is more complex (and, presumably, it is) then this may be what you are looking for.

boost signal-slot generalisation

I am searching for a way to implement something like this, using boost
class GenBoost{
boost::signal<void(void)> m_signal;
std::function<void (bool)> m_function
public:
void setSignal(boost::signal<void(void)> sigArg)
{
m_signal = sigArg;
}
void setFunction(std::function<void (bool)> &functionArg)
{
m_function = functionArg;
m_signal.connect(boost::bind(&GebBoost::onSignal,this,_1));
}
void onSignal(){
//do something
}
};
How can this be achieved. signal copying is not possible!?
I am not 100% sure of your intent, but assuming that onSignal() will not need to interact with m_signal (and that you only need one connection to m_signal), it appears that you can decouple m_signal from your class entirely. For example, if you really do not want the body of 'onSignal()' to be called until a 'm_function' has been set, you could do something like:
class GenBoost{
std::function<void (bool)> m_function;
boost::signals::scoped_conection m_connection;
public:
void setSignal(boost::signal<void(void)>& sigArg)
{
m_connection = sigArg.connect(boost::bind(&GebBoost::onSignal,this));
}
void setFunction(std::function<void (bool)> &functionArg)
{
m_function = functionArg;
}
void onSignal()
{
if ( m_function )
do_work();
}
void do_work()
{
//do something
}
};
Note that I stripped the last _1 from m_signal.connect(boost::bind(&GebBoost::onSignal,this,_1)); because the signal is declared as type void(void) so should be connected to a void callback. I also added the scoped_connection so that if the object of type GenBoost is destroyed before the signal it is connected to, it will automatically disconnect rather than allow the signal to retain an invalid pointer.
Alternatively, if you needed to retain a reference to the original signal, you could add back your original signal member, but as a pointer boost::signal<void(void)>* m_signal;. Then setSignal becomes:
void setSignal(boost::signal<void(void)>& sigArg)
{
m_signal = &sigArg;
m_connection = m_signal->connect(boost::bind(&GebBoost::onSignal,this));
}
I still recommend using the scoped connection and connecting in setSignal so that you ensure you only have one connection to one signal (If setSignal is called twice, the connection to the first signal is automatically disconnected). If you go the pointer route, you must externally ensure that the passed-in signal has a lifetime longer than the GenBoost object.

How and why one would use Boost signals2?

Learning c++ and trying to get familiar with some patterns. The signals2 doc clearly has a vast array of things I can do with slots and signals. What I don't understand is what types of applications (use cases) I should use it for.
I'm thinking along the lines of a state machine dispatching change events. Coming from a dynamically typed background (C#,Java etc) you'd use an event dispatcher or a static ref or a callback.
Are there difficulties in c++ with using cross-class callbacks? Is that essentially why signals2 exists?
One to the example cases is a document/view. How is this pattern better suited than say, using a vector of functions and calling each one in a loop, or say a lambda that calls state changes in registered listening class instances?
class Document
{
public:
typedef boost::signals2::signal<void ()> signal_t;
public:
Document()
{}
/* Connect a slot to the signal which will be emitted whenever
text is appended to the document. */
boost::signals2::connection connect(const signal_t::slot_type &subscriber)
{
return m_sig.connect(subscriber);
}
void append(const char* s)
{
m_text += s;
m_sig();
}
const std::string& getText() const
{
return m_text;
}
private:
signal_t m_sig;
std::string m_text;
};
and
class TextView
{
public:
TextView(Document& doc): m_document(doc)
{
m_connection = m_document.connect(boost::bind(&TextView::refresh, this));
}
~TextView()
{
m_connection.disconnect();
}
void refresh() const
{
std::cout << "TextView: " << m_document.getText() << std::endl;
}
private:
Document& m_document;
boost::signals2::connection m_connection;
};
Boost.Signals2 is not just "an array of callbacks", it has a lot of added value. IMO, the most important points are:
Thread-safety: several threads may connect/disconnect/invoke the same signal concurrently, without introducing race conditions. This is especially useful when communicating with an asynchronous subsystem, like an Active Object running in its own thread.
connection and scoped_connection handles that allow disconnection without having direct access to the signal. Note that this is the only way to disconnect incomparable slots, like boost::function (or std::function).
Temporary slot blocking. Provides a clean way to temporarily disable a listening module (eg. when a user requests to pause receiving messages in a view).
Automatic slot lifespan tracking: a signal disconnects automatically from "expired" slots. Consider the situation when a slot is a binder referencing a non-copyable object managed by shared_ptrs:
shared_ptr<listener> l = listener::create();
auto slot = bind(&listener::listen, l.get()); // we don't want aSignal_ to affect `listener` lifespan
aSignal_.connect(your_signal_type::slot_type(slot).track(l)); // but do want to disconnect automatically when it gets destroyed
Certainly, one can re-implement all the above functionality on his own "using a vector of functions and calling each one in a loop" etc, but the question is how it would be better than Boost.Signals2. Re-inventing the wheel is rarely a good idea.

Async constructor in C++11

Sometimes I need to create objects whose constructors take very long time to execute.
This leads to responsiveness problems in UI applications.
So I was wondering if it could be sensible to write a constructor designed to be called asynchronously, by passing a callback to it which will alert me when the object is available.
Below is a sample code:
class C
{
public:
// Standard ctor
C()
{
init();
}
// Designed for async ctor
C(std::function<void(void)> callback)
{
init();
callback();
}
private:
void init() // Should be replaced by delegating costructor (not yet supported by my compiler)
{
std::chrono::seconds s(2);
std::this_thread::sleep_for(s);
std::cout << "Object created" << std::endl;
}
};
int main(int argc, char* argv[])
{
auto msgQueue = std::queue<char>();
std::mutex m;
std::condition_variable cv;
auto notified = false;
// Some parallel task
auto f = []()
{
return 42;
};
// Callback to be called when the ctor ends
auto callback = [&m,&cv,&notified,&msgQueue]()
{
std::cout << "The object you were waiting for is now available" << std::endl;
// Notify that the ctor has ended
std::unique_lock<std::mutex> _(m);
msgQueue.push('x');
notified = true;
cv.notify_one();
};
// Start first task
auto ans = std::async(std::launch::async, f);
// Start second task (ctor)
std::async(std::launch::async, [&callback](){ auto c = C(callback); });
std::cout << "The answer is " << ans.get() << std::endl;
// Mimic typical UI message queue
auto done = false;
while(!done)
{
std::unique_lock<std::mutex> lock(m);
while(!notified)
{
cv.wait(lock);
}
while(!msgQueue.empty())
{
auto msg = msgQueue.front();
msgQueue.pop();
if(msg == 'x')
{
done = true;
}
}
}
std::cout << "Press a key to exit..." << std::endl;
getchar();
return 0;
}
Do you see any drawback in this design? Or do you know if there is a better approach?
EDIT
Following the hints of JoergB's answer, I tried to write a factory which will bear the responsibility to create an object in a sync or async way:
template <typename T, typename... Args>
class FutureFactory
{
public:
typedef std::unique_ptr<T> pT;
typedef std::future<pT> future_pT;
typedef std::function<void(pT)> callback_pT;
public:
static pT create_sync(Args... params)
{
return pT(new T(params...));
}
static future_pT create_async_byFuture(Args... params)
{
return std::async(std::launch::async, &FutureFactory<T, Args...>::create_sync, params...);
}
static void create_async_byCallback(callback_pT cb, Args... params)
{
std::async(std::launch::async, &FutureFactory<T, Args...>::manage_async_byCallback, cb, params...);
}
private:
FutureFactory(){}
static void manage_async_byCallback(callback_pT cb, Args... params)
{
auto ptr = FutureFactory<T, Args...>::create_sync(params...);
cb(std::move(ptr));
}
};
Your design seems very intrusive. I don't see a reason why the class would have to be aware of the callback.
Something like:
future<unique_ptr<C>> constructedObject = async(launchopt, [&callback]() {
unique_ptr<C> obj(new C());
callback();
return C;
})
or simply
future<unique_ptr<C>> constructedObject = async(launchopt, [&cv]() {
unique_ptr<C> ptr(new C());
cv.notify_all(); // or _one();
return ptr;
})
or just (without a future but a callback taking an argument):
async(launchopt, [&callback]() {
unique_ptr<C> ptr(new C());
callback(ptr);
})
should do just as well, shouldn't it? These also make sure that the callback is only ever called when a complete object is constructed (when deriving from C).
It shouldn't be too much effort to make any of these into a generic async_construct template.
Encapsulate your problem. Don't think about asynchronous constructors, just asynchronous methods which encapsulate your object creation.
It looks like you should be using std::future rather than constructing a message queue. std::future is a template class that holds a value and can retrieve the value blocking, timeout or polling:
std::future<int> fut = ans;
fut.wait();
auto result = fut.get();
I will suggest a hack using thread and signal handler.
1) Spawn a thread to do the task of the constructor. Lets call it child thread. This thread will intialise the values in your class.
2) After the constructor is completed, child thread uses the kill system call to send a signal to the parent thread. (Hint : SIGUSR1). The main thread on receiving the ASYNCHRONOUS handler call will know that the required object has been created.
Ofcourse, you can use fields like object-id to differentiate between multiple objects in creation.
My advice...
Think carefully about why you need to do such a long operation in a constructor.
I find often it is better to split the creation of an object into three parts
a) allocation
b) construction
c) initialization
For small objects it makes sense to do all three in one "new" operation. However, heavy weight objects, you really want to separate the stages. Figure out how much resource you need and allocate it. Construct the object in the memory into a valid, but empty state.
Then... do your long load operation into the already valid, but empty object.
I think I got this pattern a long time ago from reading a book (Scott Myers perhaps?) but I highly recommend it, it solves all sorts of problems. For example, if your object is a graphic object, you figure out how much memory it needs. If it fails, show the user an error as soon as possible. If not mark the object as not read yet. Then you can show it on screen, the user can also manipulate it, etc.
Initialize the object with an asynchronous file load, when it completes, set a flag in the object that says "loaded". When your update function sees it is loaded, it can draw the graphic.
It also REALLY helps with problems like construction order, where object A needs object B. You suddenly find you need to make A before B, oh no!! Simple, make an empty B, and pass it as a reference, as long as A is clever enough to know that be is empty, and wait to it is not before it uses it, all is well.
And... Not forgetting.. You can do the opposite on destruction.
Mark your object as empty first, so nothing new uses it (de-initialisation)
Free the resources, (destruction)
Then free the memory (deallocation)
The same benefits apply.
Having partially initialized objects could lead to bugs or unnecessarily complicated code, since you would have to check whether they're initialized or not.
I'd recommend using separate threads for UI and processing, and then use message queues for communicating between threads. Leave the UI thread for just handling the UI, which will then be more responsive all the time.
Place a message requesting creation of the object into the queue that the worker thread waits on, and then after the object has been created, the worker can put a message into UI queue indicating that the object is now ready.
Here's yet another pattern for consideration. It takes advantage of the fact that calling wait() on a future<> does not invalidate it. So, as long you never call get(), you're safe. This pattern's trade-off is that you incur the onerous overhead of calling wait() whenever a member function gets called.
class C
{
future<void> ready_;
public:
C()
{
ready_ = async([this]
{
this_thread::sleep_for(chrono::seconds(3));
cout << "I'm ready now." << endl;
});
}
// Every member function must start with ready_.wait(), even the destructor.
~C(){ ready_.wait(); }
void foo()
{
ready_.wait();
cout << __FUNCTION__ << endl;
}
};
int main()
{
C c;
c.foo();
return 0;
}