Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - [28]
> while (!data_ready) {
> pthread_cond_wait(&condvar, &mutex);
> }
> // Обработать данные
> printf("Потребитель: получил данные от производителя\n");
> data_ready = 0;
> pthread_cond_signal(&condvar);
> pthread_mutex_unlock(&mutex);
> }
>}
>void* producer (void *notused) {
> printf("Это поток-производитель...\n");
> while (1) {
> // Получить данные от оборудования
> // (мы имитируем это при помощи sleep(1))
> sleep(1);
> printf("Производитель: получил данные от h/w\n");
> pthread_mutex_lock(&mutex);
> while (data_ready) {
> pthread_cond_wait(&condvar, &mutex);
> }
> data_ready = 1;
> pthread_cond_signal(&condvar);
> pthread_mutex_unlock(&mutex);
> }
>}
>main() {
> printf(
> "Начало примера с производителем и потребителем...\n");
> // Создать поток-производитель и поток-потребитель
> pthread_create(NULL, NULL, producer, NULL);
> pthread_create(NULL, NULL, consumer, NULL);
> // Дать потокам немного повыполняться
> sleep(20);
>}
Этот пример в значительной степени похож на программу с применением ждущей блокировки, с небольшими отличиями (мы добавили несколько вызовов printf(), а также функцию main(), чтобы программа могла работать!) Первое отличие, которое бросается в глаза, — здесь использован новый тип данных, >pthread_cond_t
. Это просто декларация для условной переменной; мы назвали нашу условную переменную condvar.
Следующее, что видно из примера, — это то, что структура «потребителя» идентична таковой в предыдущем примере с ждущей блокировкой. Мы заменили функции pthread_sleepon_lock() и pthread_sleepon_unlock() на стандартные мутекс-ориентированные версии (pthread_mutex_lock() и pthread_mutex_unlock()). Функция pthread_sleepon_wait() была заменена на функцию pthread_cond_wait().
Основное различие здесь состоит в том, что библиотека ждущих блокировок имеет скрытый внутренний мутекс, а при использовании условных переменных мутекс передается явно. Последний способ дает нам больше гибкости.
И, наконец, обратите внимание на то, что мы использовали функцию pthread_cond_signal() вместо функции pthread_sleepon_signal() (опять же, с явной передачей мутекса).
В разделе о ждущих блокировках мы обещали обсудить различие между функциями pthread_sleepon_broadcast() и pthread_sleepon_signal(). Заодно поговорим и о различии между двумя аналогичными функциями, имеющими отношение к условным переменным: pthread_cond_signal() и pthread_cond_broadcast().
В двух словах, функция в варианте «signal» разблокирует только один поток. Например, если бы несколько потоков находилось в ожидании по функции «wait», и некий поток вызвал бы функцию pthread*_signal(), то был бы разблокирован только один из ждущих потоков. Который из них? Тот, у которого наивысший приоритет. Если имеется два или более потоков с одинаковым приоритетом, порядок «пробуждения» будет не определен. Применение же варианта pthread*_broadcast() приведет к тому что будут разблокированы все ожидающие потоки.
Разблокировать все потоки может показаться излишним. Но с другой стороны, разблокировать только один (причем случайный поток тоже не совсем корректно.
Поэтому мы должны думать, где имеет смысл использовать какой вариант. Очевидно, что если у вас только один ждущий поток, как у нас и было во всех вариантах «потребителя», функция pthread*_signal() прекрасно справится — будет разблокирован один поток, и как раз тот, который нужно (потому что других просто нет).
В ситуации с несколькими потоками в первую очередь следует выяснить: а почему они ждут? Обычно на этот вопрос есть два ответа:
• все потоки рассматриваются как эквивалентные и реально образуют пул доступных потоков, готовых к обработке некоторого запроса;
• все потоки являются уникальными, и каждый из них ждет соблюдения своего специфического условия.
В первом случае мы можем представить себе, что код всех потоков имеет примерно следующий вид:
>/*
> * cv1.c
>*/
>#include
>#include
>pthread_mutex_t mutex_data = PTHREAD_MUTEX_INITIALIZER;
>pthread_cond_t cv_data = PTHREAD_COND_INITIALIZER;
>int data;
>thread1() {
> for (;;) {
> pthread_mutex_lock(&mutex_data);
> while (data == 0) {
> pthread_cond_wait(&cv_data, &mutex_data);
> }
> // Сделать что-нибудь
> pthread_mutex_unlock(&mutex_data);
> }
>}
В этом случае абсолютно неважно, который именно из потоков получит данные — главное, чтобы хотя бы один сделал это и произвел над этими данными необходимые действия.
Однако, если ваш код подобен приведенному ниже, все будет несколько по-иному:
>/*
> * cv2.c
>*/
>#include
>#include
>pthread_mutex_t mutex_xy = PTHREAD_MUTEX_INITIALIZER;
>pthread_cond_t cv_xy = PTHREAD_COND_INITIALIZER;
>int x, y;
>int isprime(int);
>thread1() {
> for (;;) {
> pthread_mutex_lock(&mutex_xy);
> while ((x > 7) && (y != 15)) {
> pthread_cond_wait(&cv_xy, &mutex_xy);
> }
> // Сделать что-нибудь
> pthread_mutex_unlock(&mutex_xy);
> }
>}
>thread2() {
> for (;;) {
> pthread_mutex_lock(&mutex_xy);
> while (!isprime(x)) {
> pthread_cond_wait(&cv_xy, &mutex_xy);
> }
> // Сделать что-нибудь
> pthread_mutex_unlock(&smutex_xy);
> }
>}
>thread3() {
> for (;;) {
> pthread_mutex_lock(&mutex_xy);
> while (x != y) {
Одно из немногих изданий на русском языке, которое посвящено старейшей глобальной компьютерной сети "Fidonet". Сатирический справочник о жизни и смерти самого древнего сетевого сообщества, которое до сих пор существует среди нас.
В пособии излагаются основные тенденции развития организационного обеспечения безопасности информационных систем, а также подходы к анализу информационной инфраструктуры организационных систем и решению задач обеспечения безопасности компьютерных систем.Для студентов по направлению подготовки 230400 – Информационные системы и технологии (квалификация «бакалавр»).
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.Для программистов-пользователей операционной системы UNIX.
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса.
Применение виртуальных машин дает различным категориям пользователей — от начинающих до IT-специалистов — множество преимуществ. Это и повышенная безопасность работы, и простота развертывания новых платформ, и снижение стоимости владения. И потому не случайно сегодня виртуальные машины переживают второе рождение.В книге рассмотрены три наиболее популярных на сегодняшний день инструмента, предназначенных для создания виртуальных машин и управления ими: Virtual PC 2004 компании Microsoft, VMware Workstation от компании VMware и относительно «свежий» продукт — Parallels Workstation, созданный в компании Parallels.
Книга содержит подробные сведения о таких недокументированных или малоизвестных возможностях Windows XP, как принципы работы с программами rundll32.exe и regsvr32.exe, написание скриптов сервера сценариев Windows и создание INF-файлов. В ней приведено описание оснасток, изложены принципы работы с консолью управления mmc.exe и параметрами реестра, которые изменяются с ее помощью. Кроме того, рассмотрено большое количество средств, позволяющих выполнить тонкую настройку Windows XP.Эта книга предназначена для опытных пользователей и администраторов, которым интересно узнать о нестандартных возможностях Windows.