目录

Function Flow Runtime Serial Queue (C)

Overview

The FFRT serial queue is implemented based on the coroutine scheduling model. It provides efficient message queue functions and supports multiple service scenarios, such as asynchronous communication, traffic peak clipping, lock-free status and resource management, and architecture decoupling. The following functions are supported:

Example: Asynchronous Log System

The following is an example of implementing an asynchronous log system. The main thread submits the log task to the queue, and the background thread obtains the task from the queue and writes the task to the file. It ensures the log sequence and prevents the main thread from being blocked by the file write operation.

With FFRT APIs, you only need to focus on service logic implementation and do not need to pay attention to asynchronous thread management, thread security, and scheduling efficiency.

The example simplifies the logic for handling exceptions and ensuring thread security. The code is as follows:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include "hilog/log.h"
#include "ffrt/ffrt.h" // From the HarmonyOS third-party library "@ppd/ffrt"
#undef LOG_TAG
#define LOG_TAG "SerialTag"

typedef struct {
    FILE *logFile;          // Log file pointer.
    ffrt_queue_t queue;     // Task queue.
} LoggerT;

// Global Logger variable.
LoggerT* g_logger = nullptr;

// Initialize the logging system.
LoggerT *LoggerCreate(const char *filename)
{
    LoggerT *logger = (LoggerT *)malloc(sizeof(LoggerT));
    if (!logger) {
        OH_LOG_ERROR(LOG_APP, "Failed to allocate memory for LoggerT");
        return nullptr;
    }

    // Open the log file.
    logger->logFile = stdout;
    if (!logger->logFile) {
        OH_LOG_ERROR(LOG_APP, "Failed to open log file");
        free(logger);
        return nullptr;
    }
    OH_LOG_INFO(LOG_APP, "Log file opened: %{public}s", filename);

    // Create the task queue.
    logger->queue = ffrt_queue_create(ffrt_queue_serial, "logger_queue_c", NULL);
    if (!logger->queue) {
        OH_LOG_ERROR(LOG_APP, "Failed to create queue");
        fclose(logger->logFile);
        free(logger);
        return nullptr;
    }

    return logger;
}

// Destroy the logging system.
void LoggerDestroy(LoggerT *logger)
{
    if (logger) {
        // Destroy the queue.
        if (logger->queue) {
            ffrt_queue_destroy(logger->queue);
        }

        // Close the log file.
        if (logger->logFile) {
            fclose(logger->logFile);
            OH_LOG_INFO(LOG_APP, "Log file closed");
        }

        free(logger);
    }
}

// Log task.
void WriteTask(void *arg)
{
    char *message = (char *)arg;
    if (g_logger && g_logger->logFile) {
        OH_LOG_INFO(LOG_APP, "Writing message %{public}s", message);
        fflush(g_logger->logFile);
    }

    free(message);
}

// Add a log task.
void LoggerLog(LoggerT *logger, const char *message)
{
    if (!logger || !logger->queue) {
        return;
    }

    // Copy the message string.
    char *messageCopy = strdup(message);
    if (!messageCopy) {
        OH_LOG_ERROR(LOG_APP, "Failed to allocate memory for message");
        return;
    }

    ffrt_queue_submit_f(logger->queue, WriteTask, messageCopy, NULL);
}

int SerialQueueCExec()
{
    // Initialize the global logger.
    g_logger = LoggerCreate("log_c.txt");
    if (!g_logger) {
        return -1;
    }

    // Add a log task using the global logger.
    LoggerLog(g_logger, "Log message 1");
    LoggerLog(g_logger, "Log message 2");
    LoggerLog(g_logger, "Log message 3");

    // Simulate the main thread continuing to execute other tasks.
    sleep(1);

    // Destroy the global logger.
    LoggerDestroy(g_logger);
    g_logger = nullptr;
    return 0;
}

The ffrt_queue_submit_h_f API can receive a naked function pointer task as a parameter. If there are pre-processing and post-processing operations on the task, refer to the ffrt_alloc_auto_managed_function_storage_base function to construct the task structure.

Available APIs

The main FFRT APIs involved in the preceding sample are as follows. For details, see the methods under ffrt_queue_t:

Name Description
ffrt_queue_create Creates a queue.
ffrt_queue_destroy Destroys a queue.
ffrt_queue_submit_f

Submits a task to the queue.

Note: This API is supported since API version 20.

  • For details about how to use FFRT C++ APIs, see Using FFRT C++ APIs.
  • When using FFRT C or C++ APIs, you can use the FFRT C++ API third-party library to simplify header file inclusion, that is, use the #include "ffrt/ffrt.h" header file inclusion statement.

Constraints