Главная » Просмотр файлов » B. Stroustrup - The C++ Programming Language

B. Stroustrup - The C++ Programming Language (794319), страница 31

Файл №794319 B. Stroustrup - The C++ Programming Language (B. Stroustrup - The C++ Programming Language) 31 страницаB. Stroustrup - The C++ Programming Language (794319) страница 312019-05-09СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 31)

The resulting output would be unpredictable and could vary between different executions of the program because the order of execution of the individual operations in the two tasks isnot defined. The program may produce ‘‘odd’’ output, such asPaHerallllel o World!When defining tasks of a concurrent program, our aim is to keep tasks completely separate exceptwhere they communicate in simple and obvious ways. The simplest way of thinking of a concurrent task is as a function that happens to run concurrently with its caller. For that to work, we justhave to pass arguments, get a result back, and make sure that there is no use of shared data inbetween (no data races).116A Tour of C++: Concurrency and UtilitiesChapter 55.3.2 Passing ArgumentsTypically, a task needs data to work upon. We can easily pass data (or pointers or references to thedata) as arguments.

Consider:void f(vector<double>& v);// function do something with vstruct F {// function object: do something with vvector<double>& v;F(vector<double>& vv) :v{vv} { }void operator()();// application operator ; §3.4.3};int main(){vector<double> some_vec {1,2,3,4,5,6,7,8,9};vector<double> vec2 {10,11,12,13,14};thread t1 {f,some_vec}; // f(some_vec) executes in a separate threadthread t2 {F{vec2}};// F(vec2)() executes in a separate threadt1.join();t2.join();}Obviously, F{vec2} saves a reference to the argument vector in F.

F can now use that array andhopefully no other task accesses vec2 while F is executing. Passing vec2 by value would eliminatethat risk.The initialization with {f,some_vec} uses a thread variadic template constructor that can acceptan arbitrary sequence of arguments (§28.6). The compiler checks that the first argument can beinvoked given the following arguments and builds the necessary function object to pass to thethread. Thus, if F::operator()() and f() perform the same algorithm, the handling of the two tasks areroughly equivalent: in both cases, a function object is constructed for the thread to execute.5.3.3 Returning ResultsIn the example in §5.3.2, I pass the arguments by non-const reference. I only do that if I expect thetask to modify the value of the data referred to (§7.7).

That’s a somewhat sneaky, but not uncommon, way of returning a result. A less obscure technique is to pass the input data by const reference and to pass the location of a place to deposit the result as a separate argument:void f(const vector<double>& v, double∗ res);// take input from v; place result in *resclass F {public:F(const vector<double>& vv, double∗ p) :v{vv}, res{p} { }void operator()();// place result in *resSection 5.3.3private:const vector<double>& v;double∗ res;};Returning Results117// source of input// target for outputint main(){vector<double> some_vec;vector<double> vec2;// ...double res1;double res2;thread t1 {f,some_vec,&res1}; // f(some_vec,&res1) executes in a separate threadthread t2 {F{vec2,&res2}};// F{vec2,&res2}() executes in a separate threadt1.join();t2.join();cout << res1 << ' ' << res2 << '\n';}I don’t consider returning results through arguments particularly elegant, so I return to this topic in§5.3.5.1.5.3.4 Sharing DataSometimes tasks need to share data.

In that case, the access has to be synchronized so that at mostone task at a time has access. Experienced programmers will recognize this as a simplification(e.g., there is no problem with many tasks simultaneously reading immutable data), but considerhow to ensure that at most one task at a time has access to a given set of objects.The fundamental element of the solution is a mutex, a ‘‘mutual exclusion object.’’ A threadacquires a mutex using a lock() operation:mutex m; // controlling mutexint sh;// shared datavoid f(){unique_lock<mutex> lck {m}; // acquire mutexsh += 7;// manipulate shared data}// release mutex implicitlyThe unique_lock’s constructor acquires the mutex (through a call m.lock()). If another thread hasalready acquired the mutex, the thread waits (‘‘blocks’’) until the other thread completes its access.Once a thread has completed its access to the shared data, the unique_lock releases the mutex (witha call m.unlock()). The mutual exclusion and locking facilities are found in <mutex>.118A Tour of C++: Concurrency and UtilitiesChapter 5The correspondence between the shared data and a mutex is conventional: the programmer simplyhas to know which mutex is supposed to correspond to which data.

Obviously, this is error-prone,and equally obviously we try to make the correspondence clear through various language means.For example:class Record {public:mutex rm;// ...};It doesn’t take a genius to guess that for a Record called rec, rec.rm is a mutex that you are supposedto acquire before accessing the other data of rec, though a comment or a better name might havehelped a reader.It is not uncommon to need to simultaneously access several resources to perform some action.This can lead to deadlock. For example, if thread1 acquires mutex1 and then tries to acquire mutex2while thread2 acquires mutex2 and then tries to acquire mutex1, then neither task will ever proceedfurther.

The standard library offers help in the form of an operation for acquiring several lockssimultaneously:void f(){// ...unique_lock<mutex> lck1 {m1,defer_lock};unique_lock<mutex> lck2 {m2,defer_lock};unique_lock<mutex> lck3 {m3,defer_lock};// ...lock(lck1,lck2,lck3);// ... manipulate shared data ...} // implicitly release all mutexes// defer_lock: don’t yet try to acquire the mutex// acquire all three locksThis lock() will only proceed after acquiring all its mutex arguments and will never block (‘‘go tosleep’’) while holding a mutex.

The destructors for the individual unique_locks ensure that themutexes are released when a thread leaves the scope.Communicating through shared data is pretty low level. In particular, the programmer has todevise ways of knowing what work has and has not been done by various tasks.

In that regard, useof shared data is inferior to the notion of call and return. On the other hand, some people are convinced that sharing must be more efficient than copying arguments and returns. That can indeed beso when large amounts of data are involved, but locking and unlocking are relatively expensiveoperations. On the other hand, modern machines are very good at copying data, especially compactdata, such as vector elements. So don’t choose shared data for communication because of ‘‘efficiency’’ without thought and preferably not without measurement.5.3.4.1 Waiting for EventsSometimes, a thread needs to wait for some kind of external event, such as another thread completing a task or a certain amount of time having passed. The simplest ‘‘event’’ is simply time passing.Consider:Section 5.3.4.1Waiting for Eventsusing namespace std::chrono;119// see §35.2auto t0 = high_resolution_clock::now();this_thread::sleep_for(milliseconds{20});auto t1 = high_resolution_clock::now();cout << duration_cast<nanoseconds>(t1−t0).count() << " nanoseconds passed\n";Note that I didn’t even have to launch a thread; by default, this_thread refers to the one and onlythread (§42.2.6).I used duration_cast to adjust the clock’s units to the nanoseconds I wanted.

See §5.4.1 and§35.2 before trying anything more complicated than this with time. The time facilities are found in<chrono>.The basic support for communicating using external events is provided by condition_variablesfound in <condition_variable> (§42.3.4).

A condition_variable is a mechanism allowing one thread towait for another. In particular, it allows a thread to wait for some condition (often called an event)to occur as the result of work done by other threads.Consider the classical example of two threads communicating by passing messages through aqueue. For simplicity, I declare the queue and the mechanism for avoiding race conditions on thatqueue global to the producer and consumer:class Message {// ...};// object to be communicatedqueue<Message> mqueue;condition_variable mcond;mutex mmutex;// the queue of messages// the variable communicating events// the locking mechanismThe types queue, condition_variable, and mutex are provided by the standard library.The consumer() reads and processes Messages:void consumer(){while(true) {unique_lock<mutex> lck{mmutex};while (mcond.wait(lck)) /* do nothing */;auto m = mqueue.front();mqueue.pop();lck.unlock();// ...

process m ...// acquire mmutex// release lck and wait;// re-acquire lck upon wakeup// get the message// release lck}}Here, I explicitly protect the operations on the queue and on the condition_variable with aunique_lock on the mutex. Waiting on condition_variable releases its lock argument until the wait isover (so that the queue is non-empty) and then reacquires it.The corresponding producer looks like this:120A Tour of C++: Concurrency and Utilitiesvoid producer(){while(true) {Message m;// ...

fill the message ...unique_lock<mutex> lck {mmutex};mqueue.push(m);mcond.notify_one();}}Chapter 5// protect operations// notify// release lock (at end of scope)Using condition_variables supports many forms of elegant and efficient sharing, but can be rathertricky (§42.3.4).5.3.5 Communicating TasksThe standard library provides a few facilities to allow programmers to operate at the conceptuallevel of tasks (work to potentially be done concurrently) rather than directly at the lower level ofthreads and locks:[1] future and promise for returning a value from a task spawned on a separate thread[2] packaged_task to help launch tasks and connect up the mechanisms for returning a result[3] async() for launching of a task in a manner very similar to calling a function.These facilities are found in <future>.5.3.5.1 future and promiseThe important point about future and promise is that they enable a transfer of a value between twotasks without explicit use of a lock; ‘‘the system’’ implements the transfer efficiently.

The basicidea is simple: When a task wants to pass a value to another, it puts the value into a promise. Somehow, the implementation makes that value appear in the corresponding future, from which it can beread (typically by the launcher of the task). We can represent this graphically:task1:task2:set_value()get()futurepromiseset_exception()valueIf we have a future<X> called fx, we can get() a value of type X from it:X v = fx.get(); // if necessary, wait for the value to get computedIf the value isn’t there yet, our thread is blocked until it arrives.

Характеристики

Тип файла
PDF-файл
Размер
18,76 Mb
Тип материала
Высшее учебное заведение

Список файлов книги

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6510
Авторов
на СтудИзбе
302
Средний доход
с одного платного файла
Обучение Подробнее