Шрифт:
Интервал:
Закладка:
Было бы удобно, если бы при поступлении новых данных от графической системы поток обработки автоматически (неявно) разблокировался и немедленно приступал к обработке, а в периоды отсутствия таких данных - простаивал в блокированном состоянии. Для реализации такой схемы мы построили синхронизирующую очередь сообщений, которая использует семафор для уведомления потока обработки о наличии новых данных. В принципе указанная задача сводится к уже упоминавшемуся ранее классу задач о синхронизации производителя и потребителя данных.
class event {
/* класс синхронизирующего события, доставляющего
уведомление о добавлении нового элемента в буфер */
public:
event() { sem_init(&_block, 0, 0); }
~event() { sem_destroy(&_block); }
void wait() { sem_wait(&_block); }
void reset() { sem_post(&_block); }
private:
sem_t _block;
};
/* шаблонный класс очереди данных */
template <class T> class CDataQueue {
public:
CDataQueue() {}
~CDataQueue() {}
void push(T _new_data) {
_data_queue.push(_new_data);
data_event.reset();
}
T pop() {
data_event.wait();
T res = _data_queue.front();
_data_queue.pop();
return res;
}
private:
std::queue<T> _data_queue;
event data_event;
};
Принцип работы CDataQueueзаключается в том, что для хранения вновь поступающих данных используется очередь, что делает практически независимыми потоки производителя и потребителя. Независимыми во всех случаях, кроме пустой очереди. Потребитель должен быть блокирован до тех пор, пока нет данных от производителя. Как только производитель внесет данные в очередь, поток потребителя разблокируется и считает эти данные. Тонкость заключается в том, что поток потребителя блокируется сам при вызове функции pop(), а разблокируется из потока производителя при вызове им функции push().
Как видите, в построении специфических средств синхронизации нет ничего сложного, вопреки часто встречающемуся утверждению, что создание средств синхронизации со специфическим поведением неадекватно трудоемко, а простейший код позволяет адаптировать возможности тривиального семафора под конкретную задачу.
А теперь хотелось бы обратить ваше внимание на тот факт, что «безопасным» использованием описанной схемы будет только вариант двух потоков — одного производителя и одного потребителя. Если несколько (более двух) потоков одновременно попробуют выполнить функции pop()или push(), начнется путаница, и чем это закончится, сказать трудно. По своей логике код обеих функций в многопоточной системе требует эксклюзивного исполнения. Чтобы обеспечить исключительный доступ к этим участкам кода, мы могли бы использовать дополнительный семафор, но есть другой вариант — специальное средство синхронизации, разработанное именно для решения задачи взаимного исключения, - мьютекс.
Мьютекс
Мьютекс (от mutual exclusion — взаимное исключение) — это один из базовых примитивов синхронизации QNX Neutrino. Этот элемент реализуется на уровне микроядра системы и имеет широкий набор атрибутов и настроек. Назначение мьютекса — защита участка кода от совместного выполнения несколькими потоками. Такой участок кода иногда называют критической секцией, и обычно он является областью модификации общих переменных или обращения к разделяемому ресурсу.
Принцип работы мьютекса заключается в следующем: при обращении потока к функции блокировки (захвата) pthread_mutex_lock()проверяется, захвачен ли уже мьютекс, и если да, то вызвавший поток блокируется до освобождения критической секции. Если же нет, то объект мьютекс запоминает, какой поток его захватил (то есть владельца) и устанавливает признак, что он захвачен.
Когда действия, которые нельзя производить совместно, закончены, поток должен вызвать функцию разблокировки (освобождения) pthread_mutex_unlock(), которая проверяет, действительно ли вызвавший ее поток является тем, который в данный момент владеет мьютексом, и если да, то она разблокирует мьютекс, после чего ОС проводит редиспетчеризацию потоков. Если есть потоки, ожидающие освобождения мьютекса, то один из таких потоков, имеющий наивысший приоритет, переводится из состояния блокирования в состояние готовности и захватывает мьютекс.
В QNX Neutrino 6.2.1 мьютекс имеет наибольшие возможности по тонкой настройке своих параметров среди всех иных элементов синхронизации. В связи с этим поведение мьютекса очень сильно зависит от того, какие значения вы присвоите его атрибутам.
Как видите, главное отличие мьютекса от семафора заключается в том, что он хранит информацию о потоке, исполняющем код критической секции. Отсюда и важнейшие свойства мьютекса. Мьютекс нельзя разблокировать из другого потока. Если поток захватил мьютекс, то только он может его «отпустить». Используя информацию о владельце (tid потока), система может изменять в нужное время приоритет владельца для разрешения проблемы инверсии приоритетов. Наконец, зная идентификатор потока, мьютекс может выделить ситуацию, когда поток, уже захвативший мьютекс, пытается захватить его повторно (одна из разновидностей deadlock — мертвой блокировки, когда не существует ни одного потока, способного отпустить мьютекс и разблокировать потоки, ожидающие освобождения этого мьютекса).
В ОС QNX возможен вариант работы мьютекса, не предусмотренный стандартом POSIX, — рекурсивный мьютекс. В этом режиме поток, владеющий мьютексом при повторном его захвате, не блокируется. Мьютекс только отмечает в своем внутреннем счетчике, сколько раз он был захвачен, и разблокируется только после равного количества освобождений (естественно, тем же потоком).
Все объявления относительно мьютексов находятся в заголовочном файле <pthread.h>, и программный код, их использующий, должен включать директиву:
#include <pthread.h>
Параметры мьютекса
Параметры мьютекса хранятся в структуре pthread_mutexattr_t, которая определена типом sync_attr_t. Эта структура должна быть, создана и определена до инициализации мьютекса, после чего может быть переопределена и использована для других объектов типа мьютекс.
- Wiki-правительство: Как технологии могут сделать власть лучше, демократию – сильнее, а граждан – влиятельнее - Бет Новек - Интернет
- Современные компьютерные технологии - Денис Тунцев - Интернет
- Информация. Собственность. Интернет. Традиция и новеллы в современном праве - Михаил Якушев - Интернет
- Электронные деньги. Интернет-платежи - Михаил Мамута - Интернет
- Wi-Fi: Все, что Вы хотели знать, но боялись спросить - А. Щербаков - Интернет
- Стартовый - Александр Александрович Интелл - Интернет / Попаданцы / Русская классическая проза
- Управление информационной безопасностью. Стандарты СУИБ (СИ) - Вадим Викторович Гребенников - Интернет
- Skype: бесплатные звонки через Интернет. Начали! - Виктор Гольцман - Интернет
- Как сделать сайт адаптивным: полезные советы - "TemplateMonster" - Интернет
- Интернет-магазин с нуля. Полное пошаговое руководство - Кристиан Акила - Интернет