[TencentOS глубокий анализ крошечного источник] (5) - семафор

семафор

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

Абстрактный, семафор является неотрицательным целым числом, каждый раз , когда семафор приобретается ( pendвремени), целое число уменьшается на единицу, а когда целое значение 0, это указывает на то, что семафор находится в неактивном состоянии, он не может быть приобретено опять же , все его задача будет пытаться попасть в состояние блокировки. Семафор, как правило, значение счетчика, значение счетчика может быть использован счетчик , который системных ресурсов (счет).

В общем, есть два семафора:

  • 0: нет накопленной postоперации количество сигнала, и может иметь задачу блокировки на этом семафора.
  • Значение: указывает на то, что один или несколько postсемафоров операции.

Обычно семафор используется для синхронизации и не исключают друг друга, так как операционная система будет обеспечивать еще один механизм для взаимного исключения (мьютекс), роль взаимного исключения взаимной блокировки лучше: взаимной блокировки имеет приоритет механизм наследования, семафоры не имеют этот механизм, в дополнении к собственнику имущества также имеет семафор, мы объясним наблюдение.

Очередь , как семафоры, есть 阻塞机制. Задачи должны ждать происходит прерывание, соответствующая обработка выполняется снова, задача может быть в блокирующем состоянии семафора ждать , пока после того, как прерывание произошло после выхода семафора, задача пробуждается , чтобы выполнить соответствующую обработку. Release ( post) семафор , когда задача сразу будет ждать изменений в состояние готовности, если наивысший приоритет задачи в готовой задачи, задача может быть выполнена немедленно, это операционная система 实时响应,实时处理«» Семафор используется в операционной системе , может повысить эффективность процесса.

Структура данных Семафор

Блок управления Семафор

TencentOS tinyРабота блока управляется с помощью семафора семафор, который представляет собой тип данных k_sem_t, множество контрольных семафора блочных элементов, есть pend_obj_tвиды pend_objи k_sem_cnt_tтипы count. В то время как pend_objнесколько похожи на объектно-ориентированное наследование, некоторые свойства, там описаны типа ресурсов ядра (например, семафоры, очереди, мьютексы и т.д., и лист ожидания list). И countэто простой переменные (который представляет собой 16-битовое беззнаковое целое), представляет собой значение семафора.

typedef struct k_sem_st {
    pend_obj_t      pend_obj;
    k_sem_cnt_t     count;
} k_sem_t;

Макроопределения связанные с семафором

В tos_config.h, количество макросов , какой сигналTOS_CFG_SEM_EN

#define TOS_CFG_SEM_EN              1u

Семафор достижения

TencentOS tinyРеализовано семафоры очень прост, только код ядра 125линии можно сказать, очень меньше.

Создать семафор

Количество сигналов в системе имеет соответствующий семафор каждый блок управления, количество сигнала в блоке управления содержит всю информацию, количество сигнала, например его очереди, что тип ресурса, а также его сигнал величину, а затем представить , природа не создать элемент управления семафором семафора блок должен инициализировать его? Очевидно, что это так. Так как последующая операция управляющего сигналом блока на величину семафора работает, блок управления, если нет информации, как она может работать Ну ~

Создание семафора функции tos_sem_create()с двумя аргументами, семафором является указателем на блок управления *sem, другой начальное значение семафора init_count, неотрицательное целое значение может, но в основном не превышает 65535.

На самом деле вызов pend_object_init()функции , чтобы контролировать количество сигнальных блоков sem->pend_objпеременных членов инициализируются, он определяется как типы ресурсов PEND_TYPE_SEM. Тогда sem->countустановка переменного члена к начальному значению суммы сигнала , прошедшее в init_count.

__API__ k_err_t tos_sem_create(k_sem_t *sem, k_sem_cnt_t init_count)
{
    TOS_PTR_SANITY_CHECK(sem);

    pend_object_init(&sem->pend_obj, PEND_TYPE_SEM);
    sem->count = init_count;
    
    return K_ERR_NONE;
}

уничтожить семафор

Семафор деструктор представляет собой блок в соответствии с управлением суммой сигнала непосредственно уничтожен, все семафоры после разрушения будут удалены, и не может использовать семафор снова, когда количество сигналов уничтожаются, он ожидает есть список задач, система необходима эти задачи будут ждать пробуждение и сообщить задача семафор был уничтожен PEND_STATE_DESTROY. А затем генерирует планировщик задач для переключения на наивысший приоритет выполнения задач.

TencentOS tiny Процесс уничтожения семафора выглядит следующим образом:

  1. Вызовите pend_is_nopending()функцию , чтобы определить , есть ли задачи , ожидающие семафор
  2. Если это так, вызовите pend_wakeup_all()функцию проснутся эти задачи, и ждать , пока задача сообщить семафор был разрушен (то есть установить ожидание состояния управления задачами переменной член блока pend_stateявляется PEND_STATE_DESTROY).
  3. Вызов pend_object_deinit()содержимого блок управления функцией семафор , чтобы очистить наиболее важными является тип управления ресурсным блока установлен PEND_TYPE_NONE, так что ребенок не сможет использовать семафор.
  4. планирование задачknl_sched()

Примечание: Если семафор блок управления ОЗУ выполнен 编译器静态分配, даже если семафор будет уничтожен, это не существует способа , чтобы освободить память. Конечно, вы можете также использовать динамический блок управления памятью для семафора выделить память, но после разрушения освобожденного хотите эту память , чтобы избежать утечек памяти.

__API__ k_err_t tos_sem_destroy(k_sem_t *sem)
{
    TOS_CPU_CPSR_ALLOC();

    TOS_PTR_SANITY_CHECK(sem);

#if TOS_CFG_OBJECT_VERIFY_EN > 0u
    if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
        return K_ERR_OBJ_INVALID;
    }
#endif

    TOS_CPU_INT_DISABLE();

    if (!pend_is_nopending(&sem->pend_obj)) {
        pend_wakeup_all(&sem->pend_obj, PEND_STATE_DESTROY);
    }

    pend_object_deinit(&sem->pend_obj);

    TOS_CPU_INT_ENABLE();
    knl_sched();

    return K_ERR_NONE;
}

Приобретать семафор

tos_sem_pend()Функция используется для получения семафора , когда семафор эффективным , когда задача, чтобы получить семафор. Когда задача приобретает семафор, номер семафора минус один доступен, когда он равен 0, то задача получения семафора будет ввести блокирующее состояние, блокируя время , timeoutуказанного пользователем, не может получить сигнал в заданное время сумма будет отправлена таймаут ожидания задание будет автоматически вернется в состояние готовности.

Получить семафор процедура выглядит следующим образом:

  1. Во-первых обнаружены входные параметры являются правильными.
  2. Анализируя сигнал для управления количеством блоков countпеременной - члена больше 0, больше , чем 0 указывает количество доступного сигнала присутствует, countсостоит значение переменной 减1задачи сбора после успешного возвращения K_ERR_NONE.
  3. Если нет семафора может блокировать приобретение текущей задачи, обратите внимание на указанное пользователем время блокировки timeoutили не блокировать TOS_TIME_NOWAIT, если не заблокирован непосредственно возвращает K_ERR_PEND_NOWAITкод ошибки.
  4. Если планировщик заблокирован knl_is_sched_locked(), вы не можете ждать операции и возвращает код ошибки K_ERR_PEND_SCHED_LOCKED, в конце концов, нужно переключить задачи, планировщик закрыта , вы не можете переключиться на другую задачу.
  5. Вызов pend_task_block()функции задача заблокирована, эта функция фактически готова быть удалены из списка задач k_rdyq.task_list_head[task_prio], и вставляется в список ожидания object->list, если время ожидания не ждать вечно TOS_TIME_FOREVER, но и время , задача вставки списка k_tick_list, время блокировки timeout, то задача о планировании knl_sched().
  6. Когда программа , чтобы сделать это pend_state2errno(), она представляет собой 任务等获取到信号量, или 等待发生了超时, а затем вызвать pend_state2errno()функцию , чтобы получить о ожидании государственного задания, чтобы посмотреть на то , что привело к задаче восстановления для запуска, и результат возвращается к призванию получить семафор задачи.

Примечание: При получении семафора от задачи блокирования операции восстановления, не обязательно , чтобы получить семафор, это может быть тайм - аут произошел, поэтому при написании программы необходимо определить , что состояние семафора приобретения, если это K_ERR_NONEто Он представляет собой успех!

__API__ k_err_t tos_sem_pend(k_sem_t *sem, k_tick_t timeout)
{
    TOS_CPU_CPSR_ALLOC();

    TOS_PTR_SANITY_CHECK(sem);
    TOS_IN_IRQ_CHECK();

#if TOS_CFG_OBJECT_VERIFY_EN > 0u
    if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
        return K_ERR_OBJ_INVALID;
    }
#endif

    TOS_CPU_INT_DISABLE();

    if (sem->count > (k_sem_cnt_t)0u) {
        --sem->count;
        TOS_CPU_INT_ENABLE();
        return K_ERR_NONE;
    }

    if (timeout == TOS_TIME_NOWAIT) { // no wait, return immediately
        TOS_CPU_INT_ENABLE();
        return K_ERR_PEND_NOWAIT;
    }

    if (knl_is_sched_locked()) {
        TOS_CPU_INT_ENABLE();
        return K_ERR_PEND_SCHED_LOCKED;
    }

    pend_task_block(k_curr_task, &sem->pend_obj, timeout);

    TOS_CPU_INT_ENABLE();
    knl_sched();

    return pend_state2errno(k_curr_task->pend_state);
}

Освободить семафор

Задача или обработки прерывания обслуживания может освободить семафор (пост), освободить природу семафора семафор блок управления от countзначения переменной - члена 加1, сигнал , представляющий количество , эффективное, но если есть задачи во время ожидания семафора, семафор контроль блок countзначения переменных - членов не изменится, потому что задача ждет , чтобы проснуться, проснуться и ждать природы задачи является ожидание для выполнения этой задачи , чтобы получить семафор семафор блок управления от countзначения переменной - члена в 减1это извилины, количество блок управления сигналом countзначение переменной - члена не изменяется.

TencentOS tinyВы можете только сделать задачу ожидания приобрести семафор, но и позволяет все задачи ждут , чтобы получить семафор. В соответствии с каждым API является tos_sem_post()с tos_sem_post_all(). Кстати точка, tos_sem_post_all()шаблон проектирования является фактически режим наблюдателя, когда изменения объекта наблюдения, то все наблюдатели будут знать , что изменилось, а именно посмотреть на книгу «Westward Design Patterns».

TencentOS tinyТам , где хороший дизайн является простым и недорогой связью, эти два вызова API интерфейсов по существу sem_do_post()функционировать , чтобы освободить семафор, но optразличных параметрами выбора различных методов обработки.

В sem_do_post()обработчик очень прост, исполнение идеи заключается в следующем:

  1. Во- первых, определить , что семафор разливалась из - за целочисленного переполнения всегда, не всегда может освободить семафор , так что countзначение переменной член 加1его, необходимо определить , что переполнение, если sem->countзначения (k_sem_cnt_t)-1, то захлестнула, не в состоянии продолжать освободить семафор, коды ошибок возвращаются K_ERR_SEM_OVERFLOW.
  2. Вызовите pend_is_nopending()функцию , чтобы определить , есть ли задачи , ожидающие семафор, если нет , то countзначение переменных - членов 加1, возвращение K_ERR_NONEпоказывает успех релиза семафора, потому что в это время нет никакой необходимости не будить планирование задач, может быть возвращены непосредственно.
  3. Если есть задачи , ожидающие семафор, то countзначение переменного - член 无需加1, прямые вызовы pend_wakeupсоответствующей задачи проснуться, задача пробуждения основана на optнераспознанных параметрах, вы можете проснуться задачей или ждете всех задачи.
  4. Для проведения планирования задач knl_sched().
__API__ k_err_t tos_sem_post(k_sem_t *sem)
{
    TOS_PTR_SANITY_CHECK(sem);

    return sem_do_post(sem, OPT_POST_ONE);
}

__API__ k_err_t tos_sem_post_all(k_sem_t *sem)
{
    TOS_PTR_SANITY_CHECK(sem);

    return sem_do_post(sem, OPT_POST_ALL);
}

__STATIC__ k_err_t sem_do_post(k_sem_t *sem, opt_post_t opt)
{
    TOS_CPU_CPSR_ALLOC();

#if TOS_CFG_OBJECT_VERIFY_EN > 0u
    if (!pend_object_verify(&sem->pend_obj, PEND_TYPE_SEM)) {
        return K_ERR_OBJ_INVALID;
    }
#endif

    TOS_CPU_INT_DISABLE();

    if (sem->count == (k_sem_cnt_t)-1) {
        TOS_CPU_INT_ENABLE();
        return K_ERR_SEM_OVERFLOW;
    }

    if (pend_is_nopending(&sem->pend_obj)) {
        ++sem->count;
        TOS_CPU_INT_ENABLE();
        return K_ERR_NONE;
    }

    pend_wakeup(&sem->pend_obj, PEND_STATE_POST, opt);

    TOS_CPU_INT_ENABLE();
    knl_sched();

    return K_ERR_NONE;
}

О том, почему судья sem->countнаходится (k_sem_cnt_t)-1от имени переполнения этого? Позвольте мне привести простой пример , в C:

#include <stdio.h>

int main()
{
    unsigned int a = ~0;
    if(a == (unsigned int)0XFFFFFFFF)
    {
        printf("OK\n");
    }
    if(a == (unsigned int)-1)
    {
        printf("OK\n");
    }
    
   printf("unsigned int a = %d \n",a);
   
   return 0;
}

输出:
OK
OK
unsigned int a = -1 

резюме

Код постное и короткое, ясное мышление, очень рекомендуется углубленное изучение ~

Я хотел бы сосредоточиться на нем!

Я приветствую внимание общественности No.

Относящийся код может ответить «19» Вернитесь в общедоступном номере.
Для получения дополнительной информации , пожалуйста , концерн «Развитие вещи IoT,» общественность номер!

рекомендация

отwww.cnblogs.com/iot-dev/p/11688950.html