Skip to content

kernel_mutexes_ru

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

Мутексы

Мутекс представляет собой метод взаимодействия задач. Можно считать мутексы обобщением семафоров и почтовых ящиков. Рекомендуется использовать мутексы для защиты структур данных, доступ к которым производится из нескольких задач (критические области).

Кроме захвата и освобождения мутексов, задачи имеют возможность обмениваться сообщениями. Задача (или несколько задач) может ожидать сообщения от мутекса, при этом задача блокируется. Другая задача может послать сообщение мутексу, при этом все ожидающие сообщения задачи переходят в выполняемое состояние и получают посланное сообщение. Посылающая задача не блокируется. Если ни одна задача не ждет сообщения, оно теряется.

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

Тип mutex_t

#include "kernel/uos.h"

typedef struct _mutex_t {
    ...
} mutex_t;

void mutex_lock (mutex_t *lock);
void mutex_unlock (mutex_t *lock);
int mutex_trylock (mutex_t *lock);
void mutex_signal (mutex_t *lock, void *message);
void *mutex_wait (mutex_t *lock);

Для работы с мутексами применяются следующие функции: | Функция | Описание | |:-----------------------|:-------------| | mutex_lock () | Захват мутекса | | mutex_unlock () | Освобождение мутекса | | mutex_trylock () | Попытка захвата мутекса | | mutex_signal () | Посылка сообщения | | mutex_wait () | Ожидание сообщения |

Функция mutex_lock()

#include "kernel/uos.h"

void mutex_lock (mutex_t *lock);

Захват мутекса. Если мутекс свободен, переключение задач не происходит. Если мутекс занят другой задачей, текущая задача блокируется до освобождения мутекса.

Если мутекс связан с аппаратным прерыванием, обработка прерывания блокируется на время удержания мутекса. Отложенное прерывание будет обработано при освобождении мутекса вызовом mutex_unlock() или mutex_wait().

Параметры

  • lock --- Мутекс, который требуется захватить.

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

Пример

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

mutex_t lock;
timer_t timer;
char stack1 [4000], stack2 [4000];

void main1 (void *data)
{
    /* Задача 1 имеет более высокий приоритет и стартует раньше */
    debug_puts ("Task 1: taking the lock\n");
    mutex_lock (&lock);

    debug_puts ("Task 1: sleeping 1 second\n");
    timer_delay (&timer, 1000);

    debug_puts ("Task 1: releasing the lock\n");
    mutex_unlock (&lock);

    task_exit (0);
}

void main2 (void *data)
{
    /* Задача 2 приостанавливается до освобождения мутекса */
    debug_puts ("Task 2: taking the lock\n");
    mutex_lock (&lock);

    debug_puts ("Task 2: got the lock\n");
    mutex_unlock (&lock);
    uos_halt ();
}

void uos_init (void)
{
    task_create (main1, 0, "task1", 2, stack1, sizeof (stack1));
    task_create (main2, 0, "task2", 1, stack2, sizeof (stack2));
    timer_init (&timer, KHZ, 10);
}

Функция mutex_unlock()

#include "kernel/uos.h"

void mutex_unlock (mutex_t *lock);

Освобождение мутекса. Если мутекс связан с аппаратным прерыванием, и за время удержания мутекса возникло прерывание, производится его обработка. Может произойти переключение задач.

Параметры

  • lock --- Мутекс, который требуется освободить.

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

Пример

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

mutex_t lock;
timer_t timer;
char stack1 [4000], stack2 [4000];

void main1 (void *data)
{
    /* Задача 1 имеет более высокий приоритет и стартует раньше */
    debug_puts ("Task 1: taking the lock\n");
    mutex_lock (&lock);

    debug_puts ("Task 1: sleeping 1 second\n");
    timer_delay (&timer, 1000);

    debug_puts ("Task 1: releasing the lock\n");
    mutex_unlock (&lock);

    task_exit (0);
}

void main2 (void *data)
{
    /* Задача 2 приостанавливается до освобождения мутекса */
    debug_puts ("Task 2: taking the lock\n");
    mutex_lock (&lock);

    debug_puts ("Task 2: got the lock\n");
    mutex_unlock (&lock);
    uos_halt ();
}

void uos_init (void)
{
    task_create (main1, 0, "task1", 2, stack1, sizeof (stack1));
    task_create (main2, 0, "task2", 1, stack2, sizeof (stack2));
    timer_init (&timer, KHZ, 10);
}

Функция mutex_trylock()

#include "kernel/uos.h"

int mutex_trylock (mutex_t *lock);

Попытка захвата мутекса. Если мутекс свободен, он захватывается. Переключение задач не происходит.

Параметры

  • lock --- Мутекс, который требуется захватить.

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

Возвращает 1 если мутекс успешно захвачен. В случае неуспеха возвращается 0.

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

Пример

TODO example mutex_trylock.c

Функция mutex_signal()

#include "kernel/uos.h"

void mutex_signal (mutex_t *lock, void *message);

Посылка сообщения мутексу. Может произойти переключение задач. Если ни одна задача не ждет сообщения, оно теряется.

Параметры

  • lock --- Мутекс, которому посылается сообщение.
  • message --- Сообщение -- произвольный указатель.

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

Пример

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

mutex_t lock;
char stack1 [4000], stack2 [4000];
struct signal1_t
{
    char str_val[10];
    int int_val;
};

void main1 (void *data)
{
    /* Задача 1 имеет более высокий приоритет и стартует раньше */
    struct signal1_t *sig; /* Здесь будет указатель на принятое сообщение (message) */
    debug_puts ("Task 1: Waiting for signal\n");
    sig = (struct signal1_t *) mutex_wait (&lock);

    debug_puts ("Task 1: Caught signal:\n");
    debug_puts ("Task 1: str_val = ");
    debug_puts (sig->str_val);
    debug_puts ("\n");

    uos_halt ();
}

void main2 (void *data)
{
    /* Задача 2 посылает сообщение */
    struct signal_t sign; /* Сообщение для Task 1 */
    sign.str_val = "Hi, Task 1";

    debug_puts ("Task 2: Sending signal to Task 1\n");
    mutex_signal (&lock, (void *) &sign);

    debug_puts ("Task 2: Sent signal to Task 1, exiting\n");
    task_exit (0);
}

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

Функция mutex_wait()

#include "kernel/uos.h"

void *mutex_wait (mutex_t *lock);

Ожидание сообщения. Текущая задача блокируется до момента, пока другая задача не пошлет сообщение мутексу вызовом mutex_signal(). Если мутекс был захвачен текущей задачей, на время ожидания он освобождается. Происходит переключение задач.

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

Если мутекс связан с аппаратным прерыванием, и за время удержания мутекса возникло прерывание, производится его обработка, затем производится аппаратное разрешение (открытие маски) данного прерывания в контроллере прерываний.

Параметры

  • lock --- Мутекс, для которого ожидается сообщение.

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

Возвращает указатель-сообщение, посланное вызовом mutex_signal().

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

Пример

TODO example mutex_wait.c
You can’t perform that action at this time.