Mistake on this page?
Report an issue in GitHub or email us

EventQueue

EventQueue class hierarchy

The EventQueue class provides a flexible queue for scheduling events. You can use the EventQueue class for synchronization between multiple threads, or to move events out of interrupt context (deferred execution of time consuming or non-ISR safe operations).

The EventQueue class is thread and ISR safe.

You can use the dispatch and dispatch_forever APIs to execute pending events. break_dispatch is to terminate the execution of events in the specified EventQueue.

Shared event queues

Mbed OS provides two shared queues software can use. This can avoid the need to create private event dispatch threads and reduce the total amount of RAM used.

EventQueue class reference

Public Member Functions
 EventQueue (unsigned size=(32 *((sizeof(struct equeue_event)+2 *sizeof(void *))-2 *sizeof(void *)+sizeof(mbed::Callback< void()>))), unsigned char *buffer=NULL)
 Create an EventQueue. More...
 ~EventQueue ()
 Destroy an EventQueue. More...
void dispatch (int ms=-1)
 Dispatch events. More...
void dispatch_forever ()
 Dispatch events without a timeout. More...
void break_dispatch ()
 Break out of a running event loop. More...
unsigned tick ()
 Millisecond counter. More...
void cancel (int id)
 Cancel an in-flight event. More...
int time_left (int id)
 Query how much time is left for delayed event. More...
void background (mbed::Callback< void(int)> update)
 Background an event queue onto a single-shot timer-interrupt. More...
int chain (EventQueue *target)
 Chain an event queue onto another event queue. More...
template<typename F , typename... Args>
int call (F f, Args...args)
 Calls an event on the queue. More...
template<typename T , typename R , typename... Args>
int call (T *obj, R(T::*method)(Args...args), Args...args)
 Calls an event on the queue. More...
template<typename F , typename... Args>
int call_in (int ms, Args...args)
 Calls an event on the queue after a specified delay. More...
template<typename T , typename R , typename... Args>
int call_in (int ms, T *obj, R(T::*method)(Args...args), Args...args)
 Calls an event on the queue after a specified delay. More...
template<typename F , typename... Args>
int call_every (int ms, F f, Args...args)
 Calls an event on the queue periodically. More...
template<typename T , typename R , typename... Args>
int call_every (int ms, T *obj, R(T::*method)(Args...args), Args...args)
 Calls an event on the queue periodically. More...
template<typename R , typename... BoundArgs, typename... Args>
Event< void(Args...)> event (R(*func)(BoundArgs...), Args...args)
 Creates an event bound to the event queue. More...
template<typename T , typename R , typename... BoundArgs, typename... ContextArgs, typename... Args>
Event< void(Args...)> event (T *obj, R(T::*method)(BoundArgs..., Args...), ContextArgs...context_args)
 Creates an event bound to the event queue. More...
template<typename R , typename... BoundArgs, typename... ContextArgs, typename... Args>
Event< void(Args...)> event (mbed::Callback< R(BoundArgs..., Args...)> cb, ContextArgs...context_args)
 Creates an event bound to the event queue. More...

Shared event queue reference

EventQueue example: deferring from interrupt context

The code executes two handler functions (rise_handler and fall_handler) in two different contexts:

  1. In interrupt context when a rising edge is detected on SW2 (rise_handler).
  2. In the context of the event loop's thread function when a falling edge is detected on SW2 (fall_handler). You can use the fall_handler function as an argument to queue.event() to specify that fall_handler runs in user context instead of interrupt context.
#include "mbed.h"

DigitalOut led1(LED1);
InterruptIn sw(SW2);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
Thread t;

void rise_handler(void) {
    printf("rise_handler in context %p\r\n", Thread::gettid());
    // Toggle LED
    led1 = !led1;
}

void fall_handler(void) {
    printf("fall_handler in context %p\r\n", Thread::gettid());
    // Toggle LED
    led1 = !led1;
}

int main() {
    // Start the event queue
    t.start(callback(&queue, &EventQueue::dispatch_forever));
    printf("Starting in context %p\r\n", Thread::gettid());
    // The 'rise' handler will execute in IRQ context
    sw.rise(rise_handler);
    // The 'fall' handler will execute in the context of thread 't'
    sw.fall(queue.event(fall_handler));
}

Shared event example: deferring from interrupt context

Like the previous example, this defers from interrupt to an event queue thread. However, rather than creating its own thread, it uses the shared event queue – potentially sharing it with other system components and saving RAM.

As the event queue is shared, you should limit the execution time of your event functions to avoid delaying other users’ events excessively.

#include "mbed.h"
#include "mbed_events.h"
 
DigitalOut led1(LED1);
InterruptIn sw(SW2);
 
void rise_handler(void) {
    // Toggle LED
    led1 = !led1;
}
 
void fall_handler(void) {
    printf("fall_handler in context %p\r\n", Thread::gettid());
    // Toggle LED
    led1 = !led1;
}
 
int main() {
    // Request the shared queue
    EventQueue *queue = mbed_event_queue();
    printf("Starting in context %p\r\n", Thread::gettid());
    // The 'rise' handler will execute in IRQ context
    sw.rise(rise_handler);
    // The 'fall' handler will execute in the context of the shared queue thread
    sw.fall(queue->event(fall_handler));
}

EventQueue example: posting events to the queue

The code below demonstrates queueing functions to be called after a delay and queueing functions to be called periodically.

#include "mbed_events.h"
#include <stdio.h>

int main() {
    // creates a queue with the default size
    EventQueue queue;

    // events are simple callbacks
    queue.call(printf, "called immediately\n");
    queue.call_in(2000, printf, "called in 2 seconds\n");
    queue.call_every(1000, printf, "called every 1 seconds\n");

    // events are executed by the dispatch method
    queue.dispatch();
}

EventQueue example: chaining events from more than one queue

Event queues easily align with module boundaries, where event dispatch can implicitly synchronize internal state. Multiple modules can use independent event queues but still be composed through the EventQueue::chain function.

#include "mbed_events.h"
#include <stdio.h>

/**
Event queues easily align with module boundaries, where internal state can be 
implicitly synchronized through event dispatch. Multiple modules can use 
independent event queues, but still be composed through the EventQueue::chain function.
**/

int main() {
    // Create some event queues with pending events
    EventQueue a;
    a.call(printf, "hello from a!\n");
    
    EventQueue b;
    b.call(printf, "hello from b!\n");
    
    EventQueue c;
    c.call(printf, "hello from c!\n");
    
    // Chain c and b onto a's event queue. Both c and b will be dispatched
    // in the context of a's dispatch function.
    c.chain(&a);
    b.chain(&a);
    
    // Dispatching a will in turn dispatch b and c, printing hello from
    // all three queues
    a.dispatch();
}

Shared event example: running the shared queue from main

To further save RAM, if you have no other work to do in your main function after initialization, you can dispatch the global event queue from there, avoiding the need to create a separate dispatch thread.

To do this, set the mbed_app.json configuration option events.shared-dispatch-from-application to true, and add a dispatch call to main, as in this example. (The prints now show the same context for startup and fall_handler).

#include "mbed.h"
#include "mbed_events.h"
 
DigitalOut led1(LED1);
InterruptIn sw(SW2);
 
void rise_handler(void) {
    // Toggle LED
    led1 = !led1;
}
 
void fall_handler(void) {
    printf("fall_handler in context %p\r\n", Thread::gettid());
    // Toggle LED
    led1 = !led1;
}
 
int main() {
    // Request the shared queue
    EventQueue *queue = mbed_event_queue();
    printf("Starting in context %p\r\n", Thread::gettid());
    // The 'rise' handler will execute in IRQ context
    sw.rise(rise_handler);
    // The 'fall' handler will execute in the context of the shared queue (actually the main thread)
    sw.fall(queue->event(fall_handler));
    // Setup complete, so we now dispatch the shared queue from main
    queue->dispatch_forever();
}

Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.