Skip to content

kernel_tasks_ru

Serge Vakulenko edited this page Aug 26, 2015 · 1 revision

Задачи

Задача представляет собой поток управления (thread). Каждая задача имеет отдельный стек.

В процессе выполнения задача может захватывать необходимые мутексы. При попытке захватить мутекс, занятый другой задачей, задача блокируется до момента освобождения мутекса. Таким образом, каждая задача может находиться в одном из двух состояний: выполняемом или заблокированном.

Каждая задача имеет целочисленную характеристику - приоритет. Если в выполняемом состоянии находится более одной задачи, будет выполняться задача с более высоким (большим) приоритетом. Приоритет задается при создании задачи и может изменяться по ходу выполнения. Нулевой, самый низкий приоритет присваивается фоновой задаче.

Для облегчения отладки каждая задача имеет также имя - текстовую строку.

Тип task_t

#include "kernel/uos.h"

typedef struct _task_t {
    ...
} task_t;

task_t *task_create (void (*func)(void*), void *arg, char *name,
    int priority, char *stack, int stacksz);
void task_exit (void *message);
void task_delete (task_t *task, void *message);
void *task_wait (task_t *task);
int task_stack_avail (task_t *task);
char *task_name (task_t *task);
int task_priority (task_t *task);
void task_set_priority (task_t *task, int priority);

Структура, описывающая задачу (поток управления). Каждая задача выполняется независимо от других. Операционная система производит переключение между задачами, всякий раз выбирая для выполнения задачу, имеющую наивысший приоритет (priority). Для упрощения отладки каждой задаче присваивается имя (name). Имеется специальная задача с именем "idle" и приоритетом 0, получающая управление при отсутствии готовых к выполнению задач.

Каждая задача имеет отдельный стек (stack), использующийся при выполнении для хранения адресов возврата и параметров вызываемых функций. В стеке также сохраняется содержимое регистров процессора при переключении задач. Память для стека содержится в структуре task_t.

Для работы с задачами применяются следующие функции: | Функция | Описание | |:-----------------------|:-------------| | task_create () | Создание задачи | | task_exit () | Завершение текущей задачи | | task_delete () | Принудительное завершение задачи | | task_wait () | Ожидание завершения задачи | | task_stack_avail () | Вычисление размера стека, не использованного задачей | | task_name () | Запрос имени задачи | | task_priority () | Запрос приоритета задачи | | task_set_priority () | Установка приоритета задачи |

Функция task_create()

#include "kernel/uos.h"

task_t *task_create (void (*func)(void*), void *arg, char *name,
    int prio, char *stack, int stacksz);

Создание новой задачи (потока) и помещение ее в очередь готовых к выполнению задач. Переключение задач не происходит.

Параметры

  • func --- Функция, которая будет вызвана при первом переключении на новую задачу. Не должна возвращать управление. Для завершения задачи следует применять функцию task_exit().
  • arg --- Данное значение будет передано в качестве аргумента при вызове функции func.
  • name --- Текстовая строка, обозначающая "имя" данной задачи. Используется при выдаче отладочных сообщений. Доступно посредством функции task_name.
  • prio --- Приоритет задачи, положительное целое значение. Задача с большим значением prio имеет более высокий приоритет.
  • stack --- Массив памяти, в которой будут размещаться структура данных задачи (task_t) и стек.
  • stacksz --- Размер массива stack в байтах. Минимальное значение зависит от процессора и выполняемой задачи. Например, для процессора AVR, рекомендуемый размер составляет 200-300 байтов. При отладке рекомендуется задать размер стека с запасом, затем с помощью функции task_stack_avail определить требуемый расход памяти для каждой задачи, и при компоновке реальной системы использовать оптимизированные значения. Для экономии стека не рекомендуется исмользовать в функциях локальные массивы и вызов alloca().

Возвращаемое значение

Возвращает указатель на структуру task_t, расположенную в массиве stack.

http://uos-embedded.googlecode.com/svn/wiki/images/tcreate_ru.png

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

char stack [400];

void hello (void *data)
{
    debug_puts ("Hello, World!\n");
    uos_halt ();
}

void uos_init (void)
{
    task_create (hello, 0, "hello", 1, stack, sizeof (stack));
}

Функция task_exit()

#include "kernel/uos.h"

void task_exit (void *status);

Завершение текущей задачи со статусом status. Происходит переключение задач.

Если некая задача ожидает посредством функции task_wait() завершения текущей задачи, она получит status в качестве возвращаемого значения.

Параметры

  • status --- Произвольный указатель, передаваемый в качестве сообщения функции task_wait().

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

task_t *task2;
char stack1 [400], stack2 [400];

void main1 (void *data)
{
    void *msg;

    /* Задача 1 имеет более высокий приоритет и стартует раньше */
    debug_puts ("Task 1: waiting for task2\n");
    msg = task_wait (task2);
    debug_printf ("Task 1: task 2 returned '%s'\n", msg);
    uos_halt ();
}

void main2 (void *data)
{
    debug_puts ("Task 2: returning 'Hello'\n");
    task_exit ("Hello");
}

void uos_init (void)
{
    task_create (main1, 0, "task1", 2, stack1, sizeof (stack1));
    task2 = task_create (main2, 0, "task2", 1, stack2, sizeof (stack2));
}

Функция task_delete()

#include "kernel/uos.h"

void task_delete (task_t *task, void *status);

Принудительное завершение указанной задачи со статусом status. Если завершаемая задача является текущей, происходит переключение задач.

Если некая задача ожидает посредством функции task_wait() завершения текущей задачи, она получит status в качестве возвращаемого значения.

Параметры

  • task --- Указатель на структуру данных завершаемой задачи.
  • status --- Произвольный указатель, передаваемый в качестве сообщения функции task_wait().

http://uos-embedded.googlecode.com/svn/wiki/images/tdelete_ru.png

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

task_t *task2;
mutex_t event;
char stack1 [400], stack2 [400], stack3 [400];

void main1 (void *data)
{
    void *msg;

    /* Задача 1 имеет самый высокий приоритет и стартует раньше.
     * Ждем завершения задачи 2. */
    debug_puts ("Task 1: waiting for task2\n");
    msg = task_wait (task2);
    debug_printf ("Task 1: task 2 returned '%s'\n", msg);
    uos_halt ();
}

void main2 (void *data)
{
    /* Задача 2 стартует второй и ждет некоего события. */
    debug_puts ("Task 2: waiting for some event\n");
    mutex_wait (&event);
}

void main3 (void *data)
{
    /* Задача 3 стартует последней и завершает задачу 2. */
    debug_puts ("Task 3: killing task 2\n");
    task_delete (task2, "Killed");
    task_exit (0);
}

void uos_init (void)
{
    task_create (main1, 0, "task1", 3, stack1, sizeof (stack1));
    task2 = task_create (main2, 0, "task2", 2, stack2, sizeof (stack2));
    task_create (main3, 0, "task3", 1, stack3, sizeof (stack3));
}

Функция task_wait()

#include "kernel/uos.h"

void *task_wait (task_t *task);

Ожидание завершения указанной задачи. Текущая задача останавливается и происходит переключение задач.

Параметры

  • task --- Задача, завершения которой ожидается.

Возвращаемое значение

Возвращает статус завершения задачи, установленный вызовами task_exit() или task_delete().

http://uos-embedded.googlecode.com/svn/wiki/images/twait_ru.png

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

task_t *task2;
char stack1 [400], stack2 [400];

void main1 (void *data)
{
    void *msg;

    /* Задача 1 имеет более высокий приоритет и стартует раньше */
    debug_puts ("Task 1: waiting for task2\n");
    msg = task_wait (task2);
    debug_printf ("Task 1: task 2 returned '%s'\n", msg);
    uos_halt ();
}

void main2 (void *data)
{
    debug_puts ("Task 2: returning 'Hello'\n");
    task_exit ("Hello");
}

void uos_init (void)
{
    task_create (main1, 0, "task1", 2, stack1, sizeof (stack1));
    task2 = task_create (main2, 0, "task2", 1, stack2, sizeof (stack2));
}

Функция task_stack_avail()

#include "kernel/uos.h"

int task_stack_avail (task_t *task);

Запрос размера неиспользованной части стека указанной задачи. Переключение задач не происходит.

Вычислить размера стека, необходимый для конкретной задачи, довольно непросто. Рекомендуется при отладке задавать размер стека с запасом, затем с помощью функции task_stack_avail определить требуемый расход памяти для каждой задачи, и при компоновке реальной системы использовать оптимизированные значения. Для экономии стека не рекомендуется исмользовать в функциях локальные массивы и вызов alloca().

Параметры

  • task --- Задача, размер стека которой требуется опросить.

Возвращаемое значение

Возвращает положительное целое значение -- размер в байтах неиспользованной части стека указанной задачи.

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

char stack [400];
task_t *task;

void hello (void *data)
{
    int unused;

    unused = task_stack_avail (task);
    debug_printf ("Stack %d bytes\n", sizeof (stack));
    debug_printf ("Unused %d bytes\n", unused);
    uos_halt ();
}

void uos_init (void)
{
    task = task_create (hello, 0, "hello", 1, stack, sizeof (stack));
}

Функция task_name()

#include "kernel/uos.h"

char *task_name (task_t *task);

Запрос имени указанной задачи. Имя задается при создании задачи и используется для отладочной печати. Переключение задач не происходит.

Параметры

  • task --- Задача, имя которой требуется запросить.

Возвращаемое значение

Возвращает указатель на текстовую строку -- имя задачи.

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

char stack [400];
task_t *task;

void hello (void *data)
{
    debug_printf ("Task name = '%s'\n", task_name (task));
    uos_halt ();
}

void uos_init (void)
{
    task = task_create (hello, 0, "hello", 1, stack, sizeof (stack));
}

Функция task_priority()

#include "kernel/uos.h"

int task_priority (task_t *task);

Запрос приоритета указанной задачи. Приоритет задается при создании задачи и может изменяться функцией task_set_priority(). Переключение задач не происходит.

Параметры

  • task --- Задача, приоритет которой требуется запросить.

Возвращаемое значение

Возвращает целое положительное значение -- приоритет указанной задачи.

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

char stack [400];
task_t *task;

void hello (void *data)
{
    debug_printf ("Task priority = %d\n", task_priority (task));
    uos_halt ();
}

void uos_init (void)
{
    task = task_create (hello, 0, "hello", 123, stack, sizeof (stack));
}

Функция task_set_priority()

#include "kernel/uos.h"

void task_set_priority (task_t *task, int priority);

Изменение приоритета указанной задачи. Если новое значение приоритета превышает приоритет текущей задачи, может произойти переключение задач.

Параметры

  • task --- Задача, приоритет которой требуется изменить.

Пример

#include "runtime/lib.h"
#include "kernel/uos.h"

char stack [400];
task_t *task;

void hello (void *data)
{
    debug_printf ("Task priority = %d\n", task_priority (task));
    task_set_priority (task, 456);
    debug_printf ("New priority = %d\n", task_priority (task));
    uos_halt ();
}

void uos_init (void)
{
    task = task_create (hello, 0, "hello", 123, stack, sizeof (stack));
}
You can’t perform that action at this time.