-
Notifications
You must be signed in to change notification settings - Fork 7
Async events
Async events enable you to marshal calls from one thread to another for event-driven applications. This is essential for multithreaded apps that interact with Event Loop functions. An event loop is one of several scenarios where you may need to marshal a call from a thread to the main thread.
All Event Loop functions (except the EventLoop_Stop function) must be called from the same thread the Event Loop is created on, by default the main thread. Failing to do so, will create undefined, frustratingly difficult to diagnose bugs in your code. You have been warned :)
typedef struct _asyncBinding {
char *name;
bool triggered;
void *data;
void (*handler)(struct _asyncBinding *handle);
} DX_ASYNC_BINDING;
void dx_asyncInit(DX_ASYNC_BINDING *async);
void dx_asyncSend(DX_ASYNC_BINDING *binding, void *data);
void dx_asyncSetInit(DX_ASYNC_BINDING *asyncSet[], size_t asyncCount);
void dx_asyncRunEvents(void);
void name(DX_ASYNC_BINDING *handle)
#define DX_ASYNC_HANDLER(name, handle) \
void name(DX_ASYNC_BINDING *handle) \
{
#define DX_ASYNC_HANDLER_END }
#define DX_DECLARE_ASYNC_HANDLER(name) void name(DX_ASYNC_BINDING *handle)
static DX_ASYNC_BINDING async_test = {.name = "async_test", .handler = async_test_handler};
static DX_ASYNC_BINDING async_test2 = {.name = "async_test2", .handler = async_test2_handler};
DX_ASYNC_BINDING *asyncSet[] = {&async_test, &async_test2};
dx_asyncSetInit(asyncSet, NELEMS(asyncSet));
Note, due to the multithreaded locking strategy, you cannot call the dx_asyncSend function from an async binding callback function. Calling dx_asyncSend from an async callback function will result in a deadlock.
DX_ASYNC_HANDLER(async_test_handler, handle)
{
// Implement task to be run on the main thread.
int value = *((int *)handle->data);
Log_Debug("Data1:%d\n", value);
// The async event will start a oneshot timer on the same thread as the event loop
dx_timerOneShotSet(&tmr_led, &(struct timespec){0,1});
}
DX_ASYNC_HANDLER_END
Create a thread, and from the thread call dx_asyncSend to trigger the associated async binding callback function. The async binding callback function will be called after pending event loop events have completed. The async binding callback function will run on the event loop thread, by default, the main thread.
static void *count_thread(void *arg)
{
int count = 0;
while (true) {
count++;
dx_asyncSend(&async_test, (void *)&count);
nanosleep(&(struct timespec){0, 20 * ONE_MS}, NULL);
}
return NULL;
}
The standard EventLoopRun pattern has been extended to check for pending async events. If there are pending async events, then dx_asyncRunEvents is called to run the pending async binding callback functions.
The
while (!terminationRequired)
{
if (asyncEventReady) {
dx_asyncRunEvents();
}
int result = EventLoop_Run(dx_timerGetEventLoop(), -1, true);
// Continue if interrupted by signal, e.g. due to breakpoint being set.
if (result == -1 && errno != EINTR) {
dx_terminate(DX_ExitCode_Main_EventLoopFail);
}
}
AzureSphereDevX Examples Wiki
- Home
- Build Tools
- Adding the DevX library
- Azure IoT Hub Messaging
- Azure IoT Hub Device Twins
- Azure IoT Hub Direct Methods
- Avnet IoT Connect messaging
- Handling multithreaded async events
- Working with GPIO
- Working with UARTS
- Working with PWM
- Working with Event Timers
- Intercore Messaging
- Application termination
- Deferring updates
- Utility functions
- Tools and scripts
- Hardware Definitions