Добавил:
t.me Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2 семестр / Литература / Язык программирования С++. Краткий курс. Страуструп

.pdf
Скачиваний:
10
Добавлен:
16.07.2023
Размер:
31.34 Mб
Скачать

Задание 1:

get ()

15.7.

Обмен информацией с заданиями

Задание2:

 

set_value()

 

set_ exception ()

281

Если у нас есть future<X> с именем fx, чение типа Х с помощью функции get () :

мы

можем

получить

из

него

зна­

Х

v

=

fx.get();

//При

необходимости

ожидаем вычисление

значения

Если

значение

еще не

готово,

наш

поток

блокируется,

пока

не

получит

требу­

емое

значение.

Если

значение

не

может

быть

вычислено,

get ()

может

сгене­

рировать

исключение

(из

системы

или

переданное

из задачи,

из

которой

мы

пытались получить это значение).

Основная цель promise -

предоставить

простые

операции

передачи

зна­

чения

(именуемые

set_value()

и

set_exception()),

соответствующие

get

()

у

future.

Имена

future

(будущее)

и

promise

(обещание)

сложились

исторически;

пожалуйста,

не

обвиняйте

и

не

благодарите меня

за этот

неогра­

ниченный

источник

каламбуров.

Если

у

вас

есть

promise

и

вам

нужно

передать

результат

типа Х

в

future,

вы можете сделать Например:

одно

из

двух:

передать

значение

или

передать

исключение.

void

f(promise<X>& рх)

//

Задание:

поместить

{

 

 

 

 

 

 

 

11 ...

 

 

 

 

 

try

{

 

 

 

 

 

 

Х

res;

 

 

 

 

 

//

... Вычисление

значения

res ...

 

 

px.set_value(res);

 

 

result

в

рх

catch

( ... ) {

11 Ой!

Не

удалось вычислить

11

Передача

исключения

в

поток future:

px.set_exception(current_exception());

res

Здесь

curren

t

_

exception

()

указывает

перехваченное

исключение.

Чтобы

обработать

исключение,

переданное

через

future,

вызывающая

get

()

функция

должна

быть

готова

где-то

его

перехватить.

Например:

void

g(future<X>& fx)

{

/ / ...

 

 

 

 

 

 

try {

 

 

 

Х

v

fx.get();

11 Задание: получение

результата из fx

//При необходимости

ожидание вычисления

282

Глава

15. Параллельные вычисления

/ / . . .

Использование v ...

catch

( ... )

{

// Ой! Не удалось

//

...

Обработка

ошибки ...

вычислить

v

Если ошибку

не

нужно

обрабатывать

в

самой

функции

g ( ) ,

код

сводится

к

минимуму:

void

g(future<X>& fx)

//

{

 

 

 

 

11 ...

 

 

 

Х

v =

fx.get();

//При

/ / . . .

Использование

v

Задание:

получение результата из

fx

необходимости

ожидание

вычисления

 

...

 

 

 

 

15.7.2.

packaged_

task

Как

мы

можем

получить

future

в

задании,

которому

нужен

результат,

и

соответствующий

promise

в

потоке,

который

должен

этот

результат

вычис­

лить?

Тип

packaged_task

предназначен

для

упрощения

настройки

заданий,

связанных

с

работой

с

future

и

promise

в

потоках.

packaged_task

пре­

доставляет

код-обертку

для

размещения

возвращаемого

значения

или

исклю­

чения

из

задачи

в

promise

(подобно

коду

из

§15.7.1).

Если

вы

попросите об

этом,

вызвав

get_future,

packaged_task

выдаст

вам

future,

соответ­

ствующее

его

promise.

Например,

мы

можем

настроить

два

задания

так,

что­

бы

каждое

суммировало

половину

элементов

vector<douЫe>,

используя

алгоритм

стандартной

библиотеки

accumula

te

()

14.3):

//

Вычисление суммы

элементов [beg:end)

с начальным значением

douЫe accurn(douЬle*

beg,

douЬle* end,

douЫe init)

{

 

 

 

 

 

return accumulate(beg,end,init);

 

init:

douЫe

comp2(vector<douЫe>& v)

{

 

 

 

 

using

Task_type

=

douЬle(douЫe*,douЫe*,douЬle);

//

Тип

задания

packaged_task<Task_type> packaged_task<Task_type>

ptO

{accum};

ptl

{accum};

// //

Упаковка задания

(т.е.

accum)

future<douЫe> future<douЫe>

fO fl

{ptO.get_future() {ptl.get_future()

}; };

//Получение //Получение

future future

ptO ptl

douЬle* thread

first = &v[O];

tl

{move(ptO),first,

 

first+v.size()/2,0};

//

Запуск

потока

для

ptO

284

Глава

15.

Параллельные

вычисления

11

Накопление

и

объединение

результатов:

return

f0.get()+fl.get()+f2.get()+f3.get();

По

сути,

async

()

отделяет

"часть

вызова"

функции

от

части

"получения

результата"

и

отделяет

их

обе

от

фактического

выполнения

задания.

Исполь­

зуя

async

(),вам

не

нужно

думать

о

потоках

и

блокировках.

Вместо

этого

вы

мыслите

просто

с

точки

зрения

заданий,

которые

потенциально

асинхронно

вычисляют

свои

результаты.

Существует

очевидное

ограничение:

даже

не

ду­

майте об

использовании async ()

ресурсы,

требующие блокировки.

для

задач, которые

совместно используют

При

использовании

async () вы даже не

знаете,

сколько

потоков

будет

использоваться,

потому

что

async

()

принима­

ет

решение,

основанное

на

том,

что

ей

известно

о

системных

ресурсах,

до­

сrупных

во

время

вызова.

Например,

async

()

может

проверить,

имеются

ли

какие-либо

простаивающие

ядра

(процессоры),

прежде

чем

решить,

сколько

потоков использовать.

Использование предположения

о

стоимости

вычислений

для

принятия

ре­

шения

о

запуске

потока,

такое

как

v.

size

()

<10000,

очень

примитивно

и

может

привести

к

грубым

ошибкам

производительности.

Однако

данная

кни­

га

-

не

место

для

надлежащего

обсуждения

того,

как

управлять

потоками.

Не

воспринимайте

эrу

оценку

как

нечто

большее,

чем

простое

и,

вероятно,

неправильное предположение.

Редко бывает необходимо вручную

распараллеливать

алгоритм

стандарт­

ной

библиотеки,

такой

как

accumula

te

()

,

потому

что

готовые

параллельные

алгоритмы,

такие

как

reduce

(par_unseq,

/*

... */),обычно

лучше

с

этим

справляются

(§14.3.

1).

Тем

не

менее

такая

методика

широко

применима.

Обратите

внимание,

что

а

s

ync

( )

-

это

не

просто

механизм,

предназна­

ченный

для

параллельных

вычислений

для

повышения

производительности.

Например,

его также

можно

использовать

для

запуска

задания

для

получения

информации

от

пользователя,

оставляя

"основную

программу"

заниматься

чем-то

другим(§

15.7.3).

15.8.

Советы

[1]

[2]

[3] [4]

Используйте параллельность для снижения

времени отклика

или

для

повышения пропускной способности; §15.1.

 

 

 

Работайте на самом высоком уровне абстракции, который можете

себе

позволить; §15.1.

 

 

 

 

Рассматривайте процессы

как альтернативы

потокам; §15.1.

 

 

Средства параллельности

стандартной библиотеки безопасны

с точки

зрения типов;§15.1.

 

 

 

 

16

История

и

совместимость

• •

Поспешай медленно

 

(festina lente)

-

Октавиан Август

История

 

Временная диаграмма развития С++

Ранние годы

 

Стандарты 150 С++

 

Стандарты и стиль

 

Использование С++

 

Эволюция возможностей С++

Возможности языка С++11

 

Возможности языка С++14

Возможности языка С++17

Компоненты стандартной

библиотеки С++11

Компоненты стандартной

библиотеки С++14

Компоненты стандартной

библиотеки С++17

Удаленные и нерекомендуемые возможности

Совместимость С/С++

 

С и С++ -братья

 

Проблемы совместимости

 

Проблемы стиля

 

void*

 

Компоновка

 

Список литературы

 

Советы

 

16.1.

История

Я

изобрел С++,

написал

его

первые

определения

и

создал

его

первую

реа­

лизацию.

Я

выбрал

и

сформулировал

критерии

проектирования

для

С++,

раз-