Task with empty loop

Hi guys,

I am programming a device, which should get some values from sensors and send them over the MQTT protocol back to the server. Right now, there are two ways how to connect to the internet - external LTE modem over pppos and WiFi integrated right on ESP32.

I created two tasks - MQTT and CONN. Basically, my main function spawns those two tasks.

The CONN task connects to the internet (either using WiFi or LTE modem - it depends on current settings and availability of each method) and then unlocks mutex shared with MQTT task. After this, CONN task just maintains connection - meaning it checks for disconnect events and tries to reconnect when possible, or switch between WiFi <-> LTE.

MQTT task, after unlocking from CONN connects to the broker and waits for other parts of the application to publish messages. Again, MQTT task is responsible for waiting for disconnect event to reconnect back.

Now comes my question. Is it okay to end the task with infinite while?

void task_mqtt(void *param) {

    esp_err_t ret = ESP_FAIL;

    // Wait for muttex from CONN task
    xSemaphoreTake(mqtt_semaphore_start, portMAX_DELAY);

    // Connect to the broker, start event loop
    ret = mqtt_init();
    while (ret != ESP_OK) {

        // Wait before next try
        vTaskDelay(MS_TO_TICKS(10 * 1000));

        // Try it again
        ret = mqtt_init();
    }

    // Here, MQTT should be connected to the broker
    while (1) {
        // IS THIS REQUIRED?
    }
}

The problem is that mqtt_init function contains all the code necessary to connect to the broker, it starts event loops and registers event handlers. I suppose that without the loop at the end, all code would stop. But would not the infinite loop exhaust all resources while doing nothing? Should I insert small delay? Or is this completely wrong design?

Thank you.

No, it’s not ok as it will infinitely starve all tasks with lower priority (including the idle task which, despite its name, takes up some crucial cleanup functions). Use vTaskSuspend(NULL) instead or terminate the task altogether.

EDIT: After looking over your code again, I believe you have a conceptional misunderstanding about the logic. You may want to wrap the entire function body of your MQTT task INCLUDING the wait on semaphore into your while(1) loop, because otherwise your logic would stop working after the first disconnect.

Which part of your task does the re-connection on a disconnect event? Your task_mqtt code connects to the MQTT broker and keeps re-trying in case of failure. But once a connection is established, it does nothing and loops forever.

If your intention is only to establish the first connection (with retires in case of failure), you should delete the task instead of looping forever:

vTaskDelete(NULL);

If your intention is to re-connect on a disconnect event, you need to add some code to wait for the disconnect event and then run the connection logic again:

void task_mqtt(void *param) {

    esp_err_t ret = ESP_FAIL;

    // Wait for muttex from CONN task
    xSemaphoreTake(mqtt_semaphore_start, portMAX_DELAY);

    while (1)
    {
        /* Use any mechanism to wait for a disconnect event - semaphore is just
         * an example. This assumes that the disconnect handler gives
        * disconnected_sem semaphore. */
        xSemaphoreTake(disconnected_sem, portMAX_DELAY);

        // Connect to the broker, start event loop
        ret = mqtt_init();
        while (ret != ESP_OK) {

            // Wait before next try
            vTaskDelay(MS_TO_TICKS(10 * 1000));

            // Try it again
            ret = mqtt_init();
        }
    }
}

Thanks.