Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 51
Текст из файла (страница 51)
Кроме того, большинство пользователей предпочло бы, чтобы оператор ввода отличался от оператора вывода. Рассматривались и операторы < и»ч но семантика «меньше чем» и «больше чем» так прочно укоренилась в сознании, что предложения ввода/вывода с их использованием были бы просто нечитаемы (видимо, дпя «и» дело обстоит не так). Помимо »~ого, символ ' < ' расположен на той же клавише, что и ', ', поэтому многие писали бы выражения вроде < х, у Правильно диагностировать токую ошибку было бы нелегко>. Надо сказать, что сегодня мы уже могли бы перегрузить нужной семантикой оператор «запятая» (см.
раздел 11.5.5), но в С++ образца 1984 г. это было невозможно. В именах стандартных потоков соцс, с1п и т.д. буква с означает сЬагассег (символ). Эти потоки проектировались для ввода/вывода символов. Для версии 2.0 Джерри Шварц переписал и частично перепроектировал потоковую библиотеку, чтобы она была полезна большему числу приложений и обеспечивала более высокую эффективность файлового ввода/вывода [Бс))туагг, 19891. Значительного улучшения удалось добиться благодаря выдвинутой Эндрю Кенигом 1Коеп)8, 1991] идее манипуляторов для управления такими деталями форматирования, как задание точности для вывода чисел с плавающей точкой и основания системы счисления для целых.
Например: 1пг 1 = 1234; сапа « 1 « // по умолчанию десятичная: 1234 « Ьех « 1 « ' ' // шестнадцатеричная: 462 « осс « 1 « ' 1п') // восьмеричная: 2322 Опыт, приобретенный при работе с потоками, явился основной причиной для изменения базовой системы типов и правил перегрузки. Цель — позволить, чтобы значения типа сЬаг трактовались как символы, а не короткие целые числа, как зто было в С (см. раздел 11.2.1). Например, в результате выполнения спас сп = 'Ь'т соцс « 'а' « с)т; в версии 1.0 была бы выведена строка цифр, представляющих значения кодов символов а и Ь, тогда как в версии 2.0 выводится аЬ, как и ожидалось. Библиотека )озтгеашз, поставлявшаяся с версией С(гопг 2.0, стала моделью для реализаций других поставщиков и того варианта)озггеаш, который включат в будущий стандарт.
БИИИИИИ1я Библиотеки 8.3.2. Поддержка параллельности Множество библиотек и расширений было написано с целью поддержать параллельность. Ученые мужи были твердо убеждены в том, что многопроцессорные системы вскоре получат гораздо большее распространение, чем сейчас. Насколько я могу сулить, такое убеждение поддерживается в течение вот уже 20 лет. Многопроцессорнгяе системы действительно становятся обычным делом, но то же можно сказать и о быстрых однопроцессорных машинах. Поэтому нужны, по крайней мере, две формы поддержки параллельности: многопоточность на одном процессоре и многопроцессность на нескольких.
Кроме того, дополнительные требования предъявляются к программам, предназначенным для работы в сети. Из-за этого многообразия я рекомендовал реализовывать параллелизм в б)иблиотеках, а не в самом языке. Такие языковые средства, как, скажем, задачи в Адз, были бы неудобны почти для всех пользователей. Возможно спроектировать библиотеки лля поддержки параллельности так, что по удобству и эффективности они почти не будут уступать встроенным средствам.
По, опираясь на библиотеки, можно поддержать самые разные модели параллельности, что обеспечит пользователям гораздо большее удобство, чем единая встроенная модель. Проблемы же переносимости, возникаюшие при использовании нескольких таких библиотек, можно разрешить с помощью тонкого слоя интерфейсных классов. Примеры библиотек для поддержки параллельности можно найти в [81гоцяггцр, 1980Ь1, [ЯЬор)го, 1987[, [Гацяг, 1990! и [Рагбпйгоп, 1990!.
Примеры расширений, в которых поддержаны некоторые виды параллельности, — это Сопсцггепг С++ [СеЬап), 1988], Сошроябопа! С++ [СЬапг)у, 1993[ и Много С++ [ВпЬг, 1992[. Кроме того, для поддержки потоков и облегченных процессов доступны различные коммерческие пакеты. 8.3.2.1. Пример задачи В качестве примера программы, в которой механизмы параллельности вынесены в библиотеку, приведу алгоритм нахождения простых чисел (решето Эратосфена), где каждое простое число обрабатывается отдельной задачей. В примере используются очереди из библиотеки полдержки многозадачности [81гоцяггцр, 1980Ь), куда помещаются целые числа, служащие для задач фильтрами: ))1пс1пс)е <паяя.'и> ))1пс1пйе <1ояягеан.ь> с1аяя 1пп веяяаде : расс оЬ)еся ( ьпг рпЫ1с: 1пп веяяаде)1пс и) : 1(п) !) 1пп ча1 )) ( гегпгп 1; ): В очередях хранятся сообшения от классов, производных от оЬ1 есс.
Использование имени оЬбесп доказывает, что библиотека была разработана довольно давно. В современной программе для реализации очереди я бы использовал шаблоны, чтобы обеспечить безопасность типов, но сейчас сохраню стиль, присущий Ранние библиотеки :СИИ>ИИИВ ранним библиотекам. Использование очереди для передачи одного целого числа, пожалуй, слишком расточительный, но простой прием, а очередь гарантирует необходимую синхронизацию примитивов рис ( ) и дес ( ) из разных задач. Применение очередей иллюстрирует то, как можно передавать информация> в пропессс моделирования или в системах, где нет разделяемой памяти.
с1авя ягече : риъьгс авй ( г)са11* г)еяг.; рис<го: я<ече(1пг рг<ше, г))зеао* воягсе); ); Класс, пронзволный от "ая)с, способен работать параллельно с лругими задачамн. Вся полезная работа выполняется в конструкторах задачи илн в вызываемом нз них коде. В нашем примере каждый ягече является задачей. Объект я1ече получает число нз входной очереди н проверяет, делится ли оно на простое число, связанное с ятим в1ече. Если нет — вйече передает число палыче, слслуюшему яуече. Если его нет, то мы нашли новое простое число и можем создать новый я 1ече для его представления.
в<ече::в<ече(1пг рггя1е, (()зеаг)* вопгсе) : ()евс(0) < соус « "простое1с" « рг<яе « ')и'; гог(;;) ( тпг незвале* р = (1пс незвале*) вонгсе->пес(); <пс и = р->ча1(); (пярг1по) ( 11 (г)еяс) < г)еяг->ряс(р); сопя<вне; /! найдено простое число: создать новый ооьехт я<ече сенс = пен ота11; псы я<ече(п,оевс->):еао()); ) г(е1еге р; Сообщение создается в свободной памяти и удаляется тем объектом яйече, который это сообщение получил. Задачи работают под управлением планировщика, то есть система обеспечения многозадачности — зто нс просто система сопрограмл», где управление передается явно. Чтобы завершить программу, нам понадобится создать первый яуече в функции шауп ( ): 1пс па<я() ( гпс и = 2; ПИИИИИИв Библиотеки Пла(1* г( = пен Пла11; пеи в1ече(п,с->пеас(((); // создать первый объект з1ече 1ог ((;) ( г(->рыл(пеи 1пл певеаое(ь>п((; сньвсавк->бе1ау(1); // дадим возможность поработать 1 1 8.3.2.2.
Блокировка При параллельности блокировка часто более важна, чем задача. Если программист может сказать, что требуется исключительный доступ к некоторым данным, то не всегда нужны глубокие знания о процессе, задаче, потоке и т.д. В некоторых библиотеках благодаря атому наблюдению появился стандартный интерфейс к механизмам блокировки. При переносе такой библиотеки на новую архитектуру требуется корректно реализовать этот интерфейс с учетом конкретных существующих на ней форм параллельности. Например: с1авв ьаск ( // рпЫ1с: Ьас(г(пеа1 1осха)( -1 ос(с(); 1; // поставить блокировку // снять блокировку чо1б иу гсс() ( Ьоск 1сх (с(21осх(; // использовать с(2 1 // поставить блокировку на г(2 Снятие блокировки в деструкторе упрощает код и повышает его надежность. В частности, этот стиль хорошо сочетается с механизмом исключений (см.
раздел 16.5). При таком подходе блокировку, ключевые структуры данных и стратегии можно реализовать независимо от деталей механизмов параллельности. 8.4. Другие библиотеки В этом параграфе представлен небольшой список других библиотек на С++, чтобы проиллюстрировать их разнообразие. Кроме упомянутых, су(цествует Программа будет работать, пока полностью не исчерпает системные ресурсы. Я не позаботился о ее корректном завершении.
Это далеко не самый эффективный способ вычисления простых чисел. На каждое простое число требуются одна задача и множество контекстных переключений. Программа могла бы работать как снмулятор на одном процессоре с адресным пространством, разделяемым всеми задачами, или как настоящая параллельная программа на нескольких процессорах. Я тестировал ее в режиме симулятора па ПЕС ЪАХ для 10 тыс, простых чисел (они же задачи).
Еще более удивительный вариант решета Эратосфена на С+е см. в работе [оесЬ(, 19691. Другие библиотеки 1ИИИИИИ2П множество других библиотек, и каждый месяц появляется несколько новых. Похоже, что та форма индустрии программных компонентов, появление которой специалисты предсказывали уже на протяжении многих лет — и горевали по поводу ее отсутствия, — наконец-то родилась.
Раздел назван «Другие библиотекиь, поскольку упоминаемые в нем библиотеки не оказали существенного влияния на развитие С++. Не надо понимать это как оценку их технических достоинств или важности для пользователей. В.4.1. Базовые библиотеки Существует два взгляда на то, что представляют собой базовые библиотеки— горизонтальная и вертикальная. Первая предлагает набор базовых классов, которые предположительно должны быть полезны любому программисту при работе над любым приложением.
Обычно сюда включаются основные структуры данных: динамические и контролируемые массивы, списки, ассоциативные массивы, АУ1.- деревья и т.д., а также распространенные вспомогательные классы, такие как строки, регулярные выражения, дата и время. Как правило, горизонтальную базовую библиотеку стараются сделать максимально переносимой. Целью вертикальной базовой библиотеки является предоставление полного набора сервисов для данного окружения, например Х %1пс!ов з Бузсегп, МЯ Ж!вдоем, МасАрр, или некоторого множества таких окружений.