Управлять потоками в C для каждой мелкой задачи — это боль. ? Даже самые простые задачи вынуждают возиться с k_thread_create, ждать завершения, чистить ресурсы — и всё это превращает твой код в бесконечную головную боль. ?

К счастью, в Zephyr OS есть спасение — Thread Pool: набор заранее выделенных потоков, которые берут задачи из очереди и выполняют их без лишнего мусора. Этот подход экономит ресурсы, время и твою нервную систему.


?️ Практическая реализация Thread Pool в Zephyr OS

Ниже — пример минималистичной реализации на C, готовый для использования в Zephyr:

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/ring_buffer.h>

#define THREAD_POOL_SIZE 4
#define STACK_SIZE       1024
#define QUEUE_SIZE       32

struct task {
    void(func)(void);
    void *arg;
};

struct thread_pool {
    struct k_thread threads[THREAD_POOL_SIZE];
    struct k_sem task_sem;
    struct ring_buf task_queue;
    uint8_t task_buffer[QUEUE_SIZE * sizeof(struct task)];
    bool stop;
};

K_THREAD_STACK_ARRAY_DEFINE(thread_stacks, THREAD_POOL_SIZE, STACK_SIZE);

void worker_thread(void *pool_ptr, void *unused1, void *unused2) {
    struct thread_pool *pool = (struct thread_pool *)pool_ptr;
    struct task task;

    while (true) {
        k_sem_take(&pool->task_sem, K_FOREVER);

        if (pool->stop && ring_buf_is_empty(&pool->task_queue)) {
            break;
        }

        uint32_t bytes = ring_buf_get(&pool->task_queue, &task, sizeof(task));
        if (bytes == sizeof(task)) {
            task.func(task.arg);
        }
    }
}

void thread_pool_init(struct thread_pool *pool) {
    ring_buf_init(&pool->task_queue, QUEUE_SIZE * sizeof(struct task), pool->task_buffer);
    k_sem_init(&pool->task_sem, 0, QUEUE_SIZE);
    pool->stop = false;

    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        k_thread_create(&pool->threads[i], thread_stacks[i], STACK_SIZE, worker_thread, pool, NULL, NULL,
                        K_PRIO_PREEMPT(5), 0, K_NO_WAIT);
    }
}

void thread_pool_enqueue(struct thread_pool *pool, void(func)(void), void *arg) {
    struct task task = {.func = func, .arg = arg};
    if (ring_buf_put(&pool->task_queue, &task, sizeof(task)) == sizeof(task)) {
        k_sem_give(&pool->task_sem);
    }
}

void thread_pool_destroy(struct thread_pool *pool) {
    pool->stop = true;
    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        k_sem_give(&pool->task_sem);
    }
    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        k_thread_join(&pool->threads[i], K_FOREVER);
    }
}

void sample_task(void *arg) {
    int task_id = *(int *)arg;
    printk("Task %d running on thread %p\n", task_id, k_current_get());
    k_msleep(100);
}

int main(void) {
    struct thread_pool pool;
    thread_pool_init(&pool);

    int task_ids[5] = {0, 1, 2, 3, 4};
    for (int i = 0; i < 5; i++) {
        thread_pool_enqueue(&pool, sample_task, &task_ids[i]);
    }

    k_msleep(1000);
    thread_pool_destroy(&pool);
    return 0;
}

⚙️ Как это работает

  • Размер пула: настраивается — в примере 4 потока.

  • Очередь задач: реализована через ring_buf и k_sem.

  • Выполнение: потоки ждут семафор, берут задачу, выполняют, возвращаются ждать.

  • Завершение: пул завершает работу корректно через k_thread_join — без утечек.


✅ Преимущества

  • Экономия ресурсов — не нужно постоянно создавать и удалять потоки, что важно для микроконтроллеров.

  • Скорость — потоки всегда готовы к выполнению новых задач.

  • Чистый код — однажды настроил — и забыл о хаосе ручного управления.


⚠️ Сложности

  • Порог входа — сначала нужно разобраться, как настроить пул.

  • Зависимости задач — важна синхронизация, чтобы избежать гонок.

  • Особенности железа — поведение может отличаться на разных платформах Zephyr.


? Итог

Когда потоков становится слишком много, а k_thread_create превращает проект в кашу — Thread Pool приходит на помощь. Настраиваешь один раз — и живёшь спокойно. ?

? Совет: загляни в официальную документацию Zephyr и прокачай свои проекты до индустриального уровня.


#ZephyrOS #ThreadPool #RTOS #Embedded #C


Если тебе нужна помощь с Zephyr или примерами кода — напиши комментарий! Делюсь опытом и лайфхаками. ?

Комментарии (1)


  1. Kelbon
    06.07.2025 19:06

    ничего себе, прям сами скопировали из чат гпт всю статью? Ну тут точно надо лайк дать