Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - [21]
>
, который не будет блокирован, и итерация завершится немедленно. Почему? Потому что поток, идентифицированный как >thread_ids[1]
, уже завершился. Поэтому наш цикл for просто «проскочит» остальные потоки и завершится. В этот момент мы будем знать, что вычислительные потоки синхронизированы, и теперь мы можем выводить результаты отображение.
Когда мы говорили о синхронизации функции main() по моменту завершения рабочих потоков (в параграфе «Синхронизация по отношению к моменту завершения потока», см. выше), мы упомянули два метода синхронизации: один метод с применением функции pthread_join(), который мы только что рассмотрели, и метод с применением барьера.
Возвращаясь к нашей аналогии с процессами в жилом доме, предположим, что семья пожелала где-нибудь отдохнуть на природе. Водитель садится в микроавтобус и запускает двигатель. И ждет. Водитель будет ждать до тех пор, пока все члены семьи не сядут в машину, и только затем можно будет ехать — не можем же мы кого-нибудь оставить!
Точно так происходит и в нашем примере с выводом графики на дисплей. Основной поток должен дождаться того момента, когда все рабочие потоки завершат работу, и только затем можно начинать следующую часть программы.
Однако, отметьте для себя одну важную отличительную особенность. С применением функции pthread_join() мы ожидаем завершения потоков. Это означает, что на момент ее разблокирования потоков нет больше с нами; они закончили работу и завершились.
В случае с барьером, мы ждем «встречи» определенного числа потоков у барьера. Затем, когда заданное число потоков достигнуто, мы их всех разблокируем (заметьте, что потоки при этом продолжат выполнять свою работу).
Сначала барьер следует создать при помощи функции barrier_init():
>#include
>int barrier_init(barrier_t *barrier, const barrier_attr_t *attr, int count);
Эта функция создает объект типа «барьер» по переданному ей адресу (указатель на барьер хранится в параметре barrier) и назначает ему атрибуты, которые определены в attr (мы будем использовать NULL, чтобы установить значения по умолчанию). Число потоков, которые должны вызывать функцию barrier_wait(), передается в параметре count.
После того как барьер создан, каждый из потоков должен будет вызвать функцию barrier_wait(), чтобы сообщить, что он отработал:
>#include
>int barrier_wait(barrier_t *barrier);
После того как поток вызвал barrier_wait(), он будет блокирован до тех пор, пока число потоков, указанное первоначально в параметре count функции barrier_init(), не вызовет функцию barrier_wait() (они также будут блокированы). После того как нужное число потоков выполнит вызов функции barrier_wait(), все эти потоки будут разблокированы «одновременно».
Вот пример:
>/*
>* barrier1.c
>*/
>#include
>#include
>#include
>#include
>barrier_t barrier; // Объект типа «барьер»
>void* thread1(void *not_used) {
> time_t now;
> char buf[27];
> time(&now);
> printf("Поток 1, время старта %s", ctime_r(&now, buf));
> // Выполнить вычисления
> // (вместо этого просто сделаем sleep)
> sleep(20);
> barrier_wait(&barrier);
> // После этого момента все потоки уже завершатся
> time(&now);
> printf("Барьер в потоке 1, время срабатывания %s",
> ctime_r(&now, buf));
>}
>void* thread2(void *not_used) {
> time_t now;
> char buf[27];
> time(&now);
> printf("Поток 2, время старта %s", ctime_r(&now, buf));
> // Выполнить вычисления
> // (вместо этого просто сделаем sleep)
> sleep(40);
> barrier_wait(&barrier);
> // После этого момента все потоки уже завершатся
> time(&now);
> printf("Барьер в потоке 2, время срабатывания %s",
> ctime_r(&now, buf));
>}
>main() // Игнорировать аргументы
>{
> time_t now;
> char buf[27];
> // Создать барьер со значением счетчика 3
> barrier_init(&barrier, NULL, 3);
> // Создать два потока, thread1 и thread2
> pthread_create(NULL, NULL, thread1, NULL);
> pthread_create(NULL, NULL, thread2, NULL);
> // Сейчас выполняются оба потока
> // Ждать завершения
> time(&now);
> printf("main(): ожидание у барьера, время %s",
> ctime_r(&now, buf));
> barrier_wait(&barrier);
> // После этого момента все потоки уже завершатся
> time(&now);
> printf("Барьер в main(), время срабатывания %s",
> ctime_r(&now, buf));
>}
Основной поток создал объект типа «барьер» и инициализировал его значением счетчика, равным числу потоков (включая себя!), которые должны «встретиться» у барьера, прежде чем он «прорвется». В нашем примере этот индекс был равен 3 — один для потока main(), один для потока thread1() и один для потока thread2(). Затем, как и прежде, стартуют потоки вычисления графики (в нашем случае это потоки thread1() и thread2()). Для примера вместо приведения реальных алгоритмов графических вычислений мы просто временно «усыпили» потоки, указав в них >sleep(20)
и >sleep(40)
, чтобы имитировать вычисления. Для осуществления синхронизации основной поток (main()) просто блокирует сам себя на барьере, зная, что барьер будет разблокирован только после того, как рабочие потоки аналогично присоединятся к нему.
Как упоминалось ранее, с функцией pthread_join() рабочие потоки для синхронизации главного потока с ними должны умереть. В случае же с барьером потоки живут и чувствуют себя вполне хорошо. Фактически, отработав, они просто разблокируются по функции
Одно из немногих изданий на русском языке, которое посвящено старейшей глобальной компьютерной сети "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.