ПредишенСледващото

Аз съм сигурен, запознати с компонентите на станд :: нишка. STD :: асинхронен и станд :: бъдещ стандарт стандарт библиотека (например, виж. Този отговор), които са праволинейни.

Въпреки това, аз не мога да разбера какво означава станд :: обещание. какво прави и в какви ситуации е най-добре да се използва. В стандартния документ не съдържа много информация, извън нейното резюме, и никой от тях не е лесно. нишка.

Може ли някой да даде кратко, кратък пример за ситуация, когато трябва да се STD :: обещание и където това е най-идиоматичен решение?

По думите на [futures.state] станд :: бъдеще - това е един асинхронен връщане обект ( "обект, който чете резултатите от общото състояние") и STD :: обещание - това е един асинхронен доставчик ( "обект, което дава резултат от общото състояние") че е обещание - това е нещо, което сте инсталирали резултата, така че можете да го получите от бъдещето.

Asynchronous доставчик - е, че първоначално създава често срещано състояние, посочена в бъдеще. STD :: обещание - тип доставчик асинхронен услуга, станд :: packaged_task - от друга, и вътрешният елемент станд :: асинхронен - ​​различно. Всеки един от тях може да се създаде обща състояние и ще ви предостави станд :: бъдеще, който споделя това състояние и може да направи цяло състояние готов.

STD :: асинхронен - ​​инструмент за полезност по-високо ниво, която ви дава асинхронен резултат обект и вътрешно се грижи за създаването на доставчика на асинхронни услуги, както и общото състояние на готовност при приключване на задачата. Можете да го подражава използване STD :: packaged_task (или STD :: свързват и станд :: обещание) и STD :: конец, но това е по-безопасно и по-лесно за използване STD :: асинхронен.

STD :: обещание - малко по-ниско ниво, защото ако искате да изпратите асинхронен резултат в бъдеще, но кодът, който прави резултатът е готов, не могат да бъдат завършени в една функция, подходящ за прехода към станд :: асинхронен. Например, можете да имате масив от няколко обещание ите и свързаната с бъдеще и и има една нишка, която изпълнява множество изчисления и определя резултата на всяко обещание. асинхронен само да ви позволи да се върне само един резултат, за да се върнете няколко, ще трябва да се обадя на многократно асинхронен разговор, който може да доведе до провала на ресурси.

В C ++ има два различни, макар и свързани с тях понятия: (. Потокът е нещо, което работи в същото време) асинхронен изчисление (функция, която се нарича някъде другаде) и паралелно изпълнение. Тези две са перпендикулярни концепции. Асинхронното изчисление - това е просто страхотно повикване на функцията, а поток - е контекста на изпълнение. Конци са полезни сами по себе си, но за целите на тази дискусия, аз ще ги третира като подробности за внедряване.

Съществува йерархия на абстракция за асинхронно изчисление. Да предположим, че имаме функция, която използва някои аргументи:

На първо място, ние имаме станд :: бъдещ модел. който представлява бъдещата стойност на стойност от тип Т може да бъде получена чрез получите член функция (). които ефективно синхронизира програмата, в очакване на резултатите. Алтернативно бъдещата подкрепа wait_for (). който може да се използва, за да се провери дали резултатът е вече на разположение. Фючърси следва да се разглеждат като асинхронен подмяна заместител на конвенционалните видове замяна. За нашия примерен функция очакваме STD :: бъдеще.

Сега, йерархията от най-високата до най-ниското ниво:

STD :: асинхронен. най-удобният и директен начин за извършване на асинхронен изчисление - чрез асинхронен функция шаблон. който се връща веднага подходящия бъдещето:

Ние имаме много малко контрол върху детайлите. По-специално, ние дори не знаем дали тази функция се изпълнява едновременно, последователно след GET () или всяка друга черна магия. Въпреки това, лесно може да се получи резултата, ако е необходимо:

Сега можем да помисли как да се приложи нещо като асинхронен. но така, че ние се контролира. Например, ние можем да настояваме, че функцията, изпълнявана в отделна нишка. Вече знаем, че ние можем да осигурим отделна нишка с клас станд :: нишка.

Следващата по-ниско ниво на абстракция прави точно това: STD :: packaged_task. Това е модел, който се увива функцията и осигурява бъдеще за връщането стойност на функцията, но самия обект се причинява, и предизвикателство - по преценка на потребителя. Можем да го създаде, както следва:

Бъдещето ще бъде готов след цели и прекратяване на повикването обаждане. Това е идеалната работа за отделен поток. Ние просто трябва да бъдат сигурни, да се движат със задачата до потока:

Потокът започва веднага. Ние може или да го отделят или се присъедини към него в края на обхвата, или всеки път (например, като се използват scoped_thread Антъни Уилямс, които наистина трябва да бъде в стандартната библиотека). Въпреки това, данните за използване на станд :: конец не ни засяга; Само не забравяйте да се присъединят или да ги изключите. Важно е, че всеки път, когато завършва извикване на функция, нашият резултат е готов:

Сега ние сме до най-ниското ниво: как да се приложи задача партида? Той е тук, че идва станд :: обещание. Promise - градивен елемент за бъдещето на комуникация. Важни събития:

наричайки нишка прави обещание.

Обаждащият се получава поток от бъдещи обещания.

Обещанието функции заедно с аргументи се прехвърлят в отделен поток.

Новият нишка изпълнява функцията и пълнене на перспективи.

Резултати връща входящият поток.

Например, тук е нашата собствена "опаковани предизвикателство":

Използването на този шаблон е почти същата като тази за STD :: packaged_task. Имайте предвид, че движението на целия проблем изважда обещанието. В по-сложни ситуации, можете също така изрично обещава да преместите обект в нова тема и да го функционален аргумент за функцията на конци направи, но опаковане задачи, като по-горе, изглежда е по-гъвкава и по-малко натрапчиви решение.

Извършване на изключения

Обещанията са тясно свързани с изключения. Интерфейс на обещанията не са достатъчни, за да предадат напълно състоянието му, така че всеки път, когато по изключение хвърлен обещание за работа, няма смисъл. Всички изключения са от тип станд :: future_error. която произтича от STD :: logic_error. На първо място, описание на някои ограничения:

По подразбиране построен обещание не е активна. Неактивните обещания може да умре без последствия.

Обещанието става активен, когато бъдещето се превръща чрез get_future (). Въпреки това, можете да получите само едно бъдеще!

Обещанието трябва да се извършва или чрез set_value () или с set_exception за инсталация () трябва да бъде настроен на set_exception () срок на живота му, ако неговото бъдеще трябва да се използва. Доволен обещание може да умре без последствия, и да получите () ще бъде на разположение в бъдеще. Обещай с изключение на изключение рейз съхранява в получите повикване () в бъдеще. Ако обещаеш да не умре или по стойност или чрез изключване, да () се обадя в бъдеще ще доведе до изключването на "нарушени обещания".

Ето една малка серия от тестове, които показват изключителното разнообразие от действия. Първо, ремък:

Сега за тестовете.

Случай 1: Inactive обещание

Случай 2: Активни обещания неизползван

Случай 3: Твърде много фючърси

Случай 4: Среща обещанието

Случай 5: Твърде много удовлетворение

Същото изключение set_value, ако има повече от една от стойностите или set_value set_exception.

Случай 6: Изключване

Случай 7: Счупена обещание

C ++ изпълнение разделя фючърси, определени от малки блокове

Std. бал - една от тези части.

Promise - средство за предаване на стойност връщане (или изключване) на потока, която изпълнява функция в поток, който използва бъдеще функция.

Бъдещето обект синхронизация е изградена около края на получаване на обещаната канал.

Така че, ако искате да използвате в бъдеще, ще получите обещанието, че използвате, за да получите резултат от асинхронен обработка.

Пример от страницата:

Като груба приблизителна можете да помислите станд :: обещавам на другия край на станд :: бъдеще (това не е вярно. Но, за да илюстрира можете да мислите като че ли). Страната на потребителите на връзката ще използва станд :: бъдеще за използването на данни от общото състояние, а нишката производител ще използва станд :: обещавам да пише на общото състояние.

STD :: обещание - канал или път за информацията се върна от функцията за асинхронен. STD :: бъдеще - това е механизъм за синхронизация, която прави на обаждащия се изчака, докато тя се връща на върнатата стойност, предавана на STD :: обещание (което означава, че то е определено като функция).

В асинхронен обработка има три основен обект. В момента C ++ 11 се фокусира върху две от тях.

Основните характеристики, необходими за асинхронни логика:

  1. Проблемът (логиката, опакован като обект, а functor), която ще бъде "някъде".
  2. Действително процесор - протичане на процеса, и така нататък D. Това предизвиква тези функции, когато те са на разположение, за да ги .. Погледнете модел дизайн на «Command», за да получите представа за това, как го прави основния басейн на конци работник.
  3. Процесор резултат. някой е необходимо този резултат, и той се нуждае от един обект, който ще го получи за тях. За PLO и други причини всяко очакване или синхронизация трябва да се извърши в API на настоящото ЕВРОВОК.

C ++ 11 е това, което ти казвам (1) STD :: обещание. както и (3) STD :: бъдеще. STD :: нишка - единственото нещо, което е достъпно за обществеността (2). Това е жалко, защото реални програми, необходими за контрол на потока на ресурси и памет, и повечето от тях искате да изпълните задачите в басейните, потоци, вместо да се създават и унищожават нишка за всеки малък проблем (който почти винаги предизвиква ненужни снимки на самата премиера и лесно можете да създадете ресурси Постът е дори по-лошо).

Като последна точка за обещанието на чифт / бъдеще създаден станд. get_future () и STD :: бъдеще (създаден от станд get_future (), използвайки get_future ().) - това е друга крайна точка. Това е прост метод един изстрел, което дава възможност за синхронизиране на двата потока като един поток осигурява поток от данни през друго съобщение.

Можете да мислите за него като една нишка създава обещание за предоставяне на данните и друга нишка събира обещание за бъдещето. Този механизъм се използва само веднъж.

Механизмът на обещанията / бъдеще - това е само една посока на потока, който използва метод set_value (), за да STD :: обещание set_value () за нишката, която използва GET () за STD :: бъдеще за събиране на данни. Изключение се генерира, ако метода GET () на бъдещето се нарича повече от веднъж.

Ако една тема с STD :: обещание set_value () не се използва set_value (), за да изпълни обещанията си, когато втората нишка нарича GET () на станд :: бъдеще да събира залози, вторият поток навлиза в състоянието на готовност, докато обещанието се извършва от първия поток използване STD :: обещание set_value (), когато той използва set_value () метод за изпращане на данни.

Една бележка за този пример - забавянето добавя към различни места. Тези закъснения са добавени само за да се гарантира, че различните съобщения, изпратени към конзолата с помощта на станд :: Cout. са ясни и че текстът от множество нишки, няма да се смесват.

В първата част на главната () създава три допълнителен поток и използва станд :: обещание и станд :: бъдеще за изпращане на данни между нишки. Интересен момент е, че потокът от основния поток започва, Т2, която ще чака данни от главния поток, нещо да се направи, и след това изпраща данните на третия поток е Т3, които след това да се направи нещо и изпращане на данни обратно към основния поток.

Във втората част на основната () създава две нишки и комплект от опашки, за да позволи на няколко съобщения от основната нишка, създадена от всеки от двата потока. Ние не можем да използваме станд :: обещание и станд :: бъдеще за това, тъй като обещание / следващата дуо - един изстрел и не може да се използва повторно.

Източник Sync_queue клас е Stroustrup на C ++ език за програмиране: 4-то издание.

Това просто приложение генерира следния изход.

Promise - е на другия край на жицата.

Представете си, че трябва да се получи стойността на бъдещето. изчислено метод асинхронен. Въпреки това, вие не искате тя да бъде изчислена в един конец, а вие дори не може да се създаде поток "сега" - може би, вашият софтуер е проектиран, за да изберете потока от басейна, така че не се знае кой ще изпълнява всяко спиране в края на изчисление.

Сега, след като премине този (все още неизвестен) поток / клас / организация? Вие не подмине бъдещето. тъй като това е резултата. Вие искате да мине нещо, което е свързано с бъдещето и че е на другия край на жицата. така че просто ще поискат бъдеще без никакви познания за това кой всъщност е нещо изчислителен / запис.

Това обещание. Тази дръжка е свързана с бъдещето си. Ако в бъдеще - в говорител. и с помощта на GET () да започнете да слушате, докато не видите звук, обещавам - това е микрофон; Но не само микрофонът е микрофон, свързан към един-единствен кабел към говорителя която държите. Можете да се знае кой е на другия край, но не е нужно да се знае това - просто се откаже от него и изчакайте, докато другата страна не каза нищо.

Подкрепете проекта - споделете линка, благодаря!