Execution context in Event driven programming - events

I am reading about event driven programming from the book:
Practical UML Statecharts in C/C++, 2nd Edition:
Event-Driven Programming for Embedded Systems
On page no. xxviii Introduction , the author says:
...the event-driven application must return control after handling
each event, so the execution context cannot be preserved in the
stack-based variables and the program counter as it is in a sequential
program. Instead, the event-driven application becomes a state
machine, or actually a set of collaborating state machines that
preserve the context from one event to the next in the static
variables.
I am unable to understand why the execution context cannot be preserved in the stack-based variables and the program counter once the control is returned after handling the event?

Let's start with how the traditional sequential programming paradigm works. Suppose that you want to blink an LED on an embedded board. A common solution would be to write a program like this (e.g., see Arduino Blink tutorial):
while (1) { /* RTOS task or a "superloop" */
turn_LED_on(); /* turn the LED on (computation) */
delay(500); /* wait for 500 ms (polling or blocking) */
turn_LED_off(); /* turn the LED off (computation) */
delay(1000); /* wait for 1000 ms (polling or blocking) */
}
The key point here is the delay() function, which waits in-line until the delay elapses. This waiting is called "blocking", because the calling program is blocked until delay() returns.
Please note that the Blinky program calls delay() in two different contexts: first time after turn_LED_on() and the second time after turn_LED_off(). Each time, delay() returns to a different place in the code. This means that while the program is blocked, the information about the place in the code (the context of the call) is automatically preserved.
The trivial Blinky program is very simple, but in principle a blocking function, like delay(), could be called from other functions each with
complex if-else-while code. Still, delay() will be able to return to the exact point of the call, because the C programming language preserves the context of the call (in the call stack and the program counter).
But blocking makes the whole program unresponsive to any other events and therefore people came up with event-driven programming.
An event-driven program is structured around an event-loop. An example event-driven code could look like this:
while (1) { /* event-loop */
Event *e = queue_get(); /* block when event queue is empty */
dispatch(e); /* handle the event, cannot block! */
}
The main point is that the dispatch() "event-handler" function cannot call a blocking function like delay(). Instead, dispatch() can only perform some immediate action and must quickly return back to the event-loop. That way, the event-loop remains responsive at all times.
But, by returning the dispatch() function removes its own stack frame from the call stack. So the call stack and program counter associated with calling dispatch() is always the same and is useless to "remember" the execution context.
Instead, to blink the LED, the dispatch() function must rely on some variable (state) that remembers the state (on/off) of the LED. An example how you could write such dispatch() function is as follows:
static enum {OFF, ON } state = OFF; /* start in the OFF state */
timer_arm(1000); /* arm a timer to generate TIMEOUT event in 1000 ms */
void dispatch(Event *e) {
switch (state) {
case OFF:
if (e->sig == TIMEOUT) {
turn_LED_on();
timer_arm(500);
state = ON; /* transition to "ON" state */
}
break;
case ON:
if (e->sig == TIMEOUT) {
turn_LED_off();
timer_arm(1000);
state = OFF; /* transition to "OFF" state */
}
break;
}
}
I hope you can see that dispatch() implements a state machine with states ON and OFF driven by one event TIMEOUT.

Related

Is * operator of std::shared_ptr thread safe?

I have a std::shared_ptr which changes asynchronously from a callback.
In main thread, I want to read the "latest" value and do complex calculations on it, and I do not care if the pointer's value changes while those calculations are running.
For this, I am simply making a copy of the contained value on the main thread:
// async thread
void callback(P new_data) {
smart_pointer_ = new_data;
}
// main thread loop!
Value copy_of_pointer_value = *smart_pointer_; // smart_pointer_ could be changing in callback right now
// do calcs with copy_of_pointer_value
Is this safe or should I be explicitly making a copy of the smart pointer before trying to read its value, like this:
// main thread loop!
auto smart_copy = smart_pointer_;
// I know I could work with *smart_copy directly, but I need to copy anyway for other reasons
Value copy_of_pointer_value = *smart_copy;
// do calcs with copy_of_pointer_value

Avoiding deadlock in reentrant code C++11

I am working on refactoring some legacy code that suffers from deadlocks. There are two main root causes:
1) the same thread locking the same mutex multiple times, which should not difficult to resolve, and
2) the code occasionally calls into user defined functions which can enter the same code at the top level. I need to lock the mutex before calling user defined functions, but I might end up executing the same code again which will result in a deadlock situation. So, I need some mechanism to tell me that the mutex has already been locked and I should not lock it again. Any suggestions?
Here is a (very) brief summary of what the code does:
class TreeNode {
public:
// Assign a new value to this tree node
void set(const boost::any& value, boost::function<void, const TreeNode&> validator) {
boost::upgrade_lock<boost::shared_mutex> lock(mutexToTree_);
// call validator here
boost::upgrade_to_unique_lock<boost::shared_mutex> ulock(lock);
// set this TreeNode to value
}
// Retrieve the value of this tree node
boost::any get() {
boost::shared_lock<boost::shared_mutex> lock(mutexToTree_);
// get value for this tree node
}
private:
static boost::shared_mutex mutexToRoot_;
};
The problem is that the validator function can call into get(), which locks mutexToRoot_ on the same thread. I could modify mutexToRoot_ to be a recursive mutex but that would prevent other threads from reading the tree during get() operation, which is unwanted behavior.
Since C++11 you can use std::recursive_mutex, which allows the owning thread to call lock or try_lock without blocking/reporting failure, whereas the other threads will block on lock/receive false on try_lock until the owning thread calls unlock as many times as it called lock/try_lock before.

C++ memory management patterns for objects used in callback chains

A couple codebases I use include classes that manually call new and delete in the following pattern:
class Worker {
public:
void DoWork(ArgT arg, std::function<void()> done) {
new Worker(std::move(arg), std::move(done)).Start();
}
private:
Worker(ArgT arg, std::function<void()> done)
: arg_(std::move(arg)),
done_(std::move(done)),
latch_(2) {} // The error-prone Latch interface isn't the point of this question. :)
void Start() {
Async1(<args>, [=]() { this->Method1(); });
}
void Method1() {
StartParallel(<args>, [=]() { this->latch_.count_down(); });
StartParallel(<other_args>, [=]() { this->latch_.count_down(); });
latch_.then([=]() { this->Finish(); });
}
void Finish() {
done_();
// Note manual memory management!
delete this;
}
ArgT arg_
std::function<void()> done_;
Latch latch_;
};
Now, in modern C++, explicit delete is a code smell, as, to some extent is delete this. However, I think this pattern (creating an object to represent a chunk of work managed by a callback chain) is fundamentally a good, or at least not a bad, idea.
So my question is, how should I rewrite instances of this pattern to encapsulate the memory management?
One option that I don't think is a good idea is storing the Worker in a shared_ptr: fundamentally, ownership is not shared here, so the overhead of reference counting is unnecessary. Furthermore, in order to keep a copy of the shared_ptr alive across the callbacks, I'd need to inherit from enable_shared_from_this, and remember to call that outside the lambdas and capture the shared_ptr into the callbacks. If I ever wrote the simple code using this directly, or called shared_from_this() inside the callback lambda, the object could be deleted early.
I agree that delete this is a code smell, and to a lesser extent delete on its own. But I think that here it is a natural part of continuation-passing style, which (to me) is itself something of a code smell.
The root problem is that the design of this API assumes unbounded control-flow: it acknowledges that the caller is interested in what happens when the call completes, but signals that completion via an arbitrarily-complex callback rather than simply returning from a synchronous call. Better to structure it synchronously and let the caller determine an appropriate parallelization and memory-management regime:
class Worker {
public:
void DoWork(ArgT arg) {
// Async1 is a mistake; fix it later. For now, synchronize explicitly.
Latch async_done(1);
Async1(<args>, [&]() { async_done.count_down(); });
async_done.await();
Latch parallel_done(2);
RunParallel([&]() { DoStuff(<args>); parallel_done.count_down(); });
RunParallel([&]() { DoStuff(<other_args>); parallel_done.count_down(); };
parallel_done.await();
}
};
On the caller-side, it might look something like this:
Latch latch(tasks.size());
for (auto& task : tasks) {
RunParallel([=]() { DoWork(<args>); latch.count_down(); });
}
latch.await();
Where RunParallel can use std::thread or whatever other mechanism you like for dispatching parallel events.
The advantage of this approach is that object lifetimes are much simpler. The ArgT object lives for exactly the scope of the DoWork call. The arguments to DoWork live exactly as long as the closures containing them. This also makes it much easier to add return-values (such as error codes) to DoWork calls: the caller can just switch from a latch to a thread-safe queue and read the results as they complete.
The disadvantage of this approach is that it requires actual threading, not just boost::asio::io_service. (For example, the RunParallel calls within DoWork() can't block on waiting for the RunParallel calls from the caller side to return.) So you either have to structure your code into strictly-hierarchical thread pools, or you have to allow a potentially-unbounded number of threads.
One option is that the delete this here is not a code smell. At most, it should be wrapped into a small library that would detect if all the continuation callbacks were destroyed without calling done_().

How to use wake_up_interruptible

I wonder how can I use wake_up_interruptible, if it returns void: http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/linux/wait.h#L161 (_wake_up function returns void). For example, down_interruptible function returns int: http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/kernel/semaphore.c#L75 This allows to write such code, for example:
if ( down_interruptible(&dev->sem) )
return -ERESTARTSYS;
// continue: down_interruptible succeeded
When I call wake_up_interruptible, and it is interrupted, how can I know this, if it returns void?
i suppose normal usage scenario would be, in one thread:
for (;;) {
wait_event_interruptible(wait_queue, condition);
/* Some processing */
}
and from some other thread:
if (something_happened)
wake_up_interruptible(wait_queue);
which will result in one process from wait_queue which is in TASK_INTERRUPTIBLE state to be woken up and evalueate condition
see some more examples here, a bit dated bit gives an idea

boost signals - How control lifetime of objects sent to subscribers? Smart pointers?

I am using boost::signals2 under Red Hat Enterprise Linux 5.3.
My signal creates an object copy and sends it's pointer to subscribers. This was implemented for thread safety to prevent the worker thread from updating a string property on the object at the same time it is being read ( perhaps I should revisit the use of locks? ).
Anyway, my concern is with multiple subscribers that dereference the pointer to the copied object on their own thread. How can I control object lifetime? How can I know all subscribers are done with the object and it is safe to delete the object?
typedef boost::signals2::signal< void ( Parameter* ) > signalParameterChanged_t;
signalParameterChanged_t m_signalParameterChanged;
// Worker Thread - Raises the signal
void Parameter::raiseParameterChangedSignal()
{
Parameter* pParameterDeepCopied = new Parameter(*this);
m_signalParameterChanged(pParameterDeepCopied);
}
// Read-Only Subscriber Thread(s) - GUI (and Event Logging thread ) handles signal
void ClientGui::onDeviceParameterChangedHandler( Parameter* pParameter)
{
cout << pParameter->toString() << endl;
delete pParameter; // **** This only works for a single subscriber !!!
}
Thanks in advance for any tips or direction,
-Ed
If you really have to pass Parameter by pointer to your subscribers, then you should use boost::shared_ptr:
typedef boost::shared_ptr<Parameter> SharedParameterPtr;
typedef boost::signals2::signal< void ( SharedParameterPtr ) > signalParameterChanged_t;
signalParameterChanged_t m_signalParameterChanged;
// The signal source
void Parameter::raiseParameterChangedSignal()
{
SharedParameterPtr pParameterDeepCopied = new Parameter(*this);
m_signalParameterChanged(pParameterDeepCopied);
}
// The subscriber's handler
void ClientGui::onDeviceParameterChangedHandler( SharedParameterPtr pParameter)
{
cout << pParameter->toString() << endl;
}
The shared parameter object sent to your subscribers will be automatically deleted when its reference count becomes zero (i.e. it goes out of scope in all the handlers).
Is Parameter really so heavyweight that you need to send it to your subscribers via pointer?
EDIT:
Please note that using shared_ptr takes care of lifetime management, but will not relieve you of the responsibility to make concurrent reads/writes to/from the shared parameter object thread-safe. You may well want to pass-by-copy to your subscribers for thread-safety reasons alone. In your question, it's not clear enough to me what goes on thread-wise, so I can't give you more specific recommendations.
Is the thread calling raiseParameterChangedSignal() the same as your GUI thread? Some GUI toolkits don't allow concurrent use of their API by multiple threads.

Resources