File: async.yo

package info (click to toggle)
c%2B%2B-annotations 10.6.0-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 10,536 kB
  • ctags: 3,247
  • sloc: cpp: 19,157; makefile: 1,521; ansic: 165; sh: 128; perl: 90
file content (153 lines) | stat: -rw-r--r-- 7,543 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
In this section the function template hi(async)tt(std::async) is
covered. tt(Async) is used to start asynchronous tasks, returning values (or
tt(void)) to the calling thread, which is hard to realize merely using the
tt(std::thread) class.

Before using the function tt(async) the tthi(future) header file must be
included. 

When starting a thread using the facilities of the class tt(std::thread) the
initiating thread at some point commonly calls the thread's tt(join)
method. At that point the thread must have finished or execution blocks until
tt(join) returns. While this often is a sensible course of action, it may not
always be: maybe the function implementing the thread has a return value, or
it could throw an exception.

In those cases tt(join) cannot be used: if an exception leaves a thread, then
your program ends. Here is an example:
    verbinclude(-ns4 //code examples/throwing.cc)
    In line 3 tt(thrower) throws an exception, leaving the thread. This
exception is not caught by tt(main)'s try-block (as it is defined in another
thread). As a consequence, the program terminates.

This scenario doesn't occur when tt(std::async) is used. tt(Async) may start a
new asynchronous task, and the activating thread may retrieve the return value
of the function implementing the asynchronous task or any exception leaving
that function from a tt(std::future) object returned by the tt(async)
function. Basically, tt(async) is called similarly to the way a thread is
started using tt(std::thread): it is passed a function and optionally
arguments which are forwarded to the function.

Although the function implementing the asynchronous task may be passed as
first argument, tt(async) first argument may also be a value of the strongly
typed enumeration hi(deferred)hi(async)hi(launch)tt(std::launch):
        verb(
    enum class launch
    {
        async,
        deferred
    };
        )
    When passing tt(launch::async) the asynchronous task immediately starts;
when passing tt(launch::deferred) the asynchronous task is deferred. When 
tt(std::launch) is not specified the default value tt(launch::async |
launch::deferred) is used, giving the implementation freedom of choice, 
usually resulting in deferring execution of the asynchronous task.

So, here is the first example again, this time using tt(async) to start the
sub-thread:
    verbinclude(-ns4 //code examples/async1.cc)
    Now the threads immediately start, but although the results are
available around line 13, the thrown exception isn't terminating the
program. The first thread's return value is made available in line 16, the
exception thrown by the second thread is simply caught by main's try-block
(line 19).

The function template tt(async) has several overloaded versions:
    itemization(
    it() The basic form expects a function or functor as its first argument,
returning a tt(std::future) holding the function's return value or  exception
thrown by the function:
        verb(
    template <typename Function, class ...Args>
    std::future<
        typename std::result_of< Function(Args ...) >::type
    > std::async(Function &&fun, Args &&...args);
        )

    it() Alternatively, the first argument may be the address of a member
function. In that case the (required) second argument is an object (or a
pointer to an object) of that member function's class. Any remaining arguments
are passed to the member function (see also the remarks below).

    it() The first argument may also be a combination (using the tt(bit_or)
operator) of the enumeration values of the tt(std::launch) enumeration:
        verb(
    template <class Function, class ...Args>
    std::future<typename std::result_of<Function(Args ...)>::type> 
        std::async(std::launch policy, Function &&fun, Args &&...args);
        )

    it() If the first argument specifies tt(std::launch) values, the second
argument may also be the address of a member function.  In that case the
(required) thirs argument is an object (or a pointer to an object) of that
member function's class. Any remaining arguments are passed to the member
function (see also the remarks below).
    )
    When calling tt(async) all arguments except for the tt(std::launch)
argument must be references, pointers or move-constructible objects:
   itemization(
   it() When a
    member function is specified, then the object for which the member
    function is called must be a named object, an anonymous object, or a
    pointer to a named object. 
   it() When a named object is passed to the tt(async) function template then
    copy construction is used to construct a copy of the argument which is
    then forwarded to the thread-launcher. 
   it() When an anonymous object is passed to the tt(async) function template
    then move construction is used to forward the anonymous object to the
    thread launcher. 
   )
 Once the thread itself starts another move construction is used to construct
an object for the duration of the thread. When a pointer to an object is
passed, the sub-thread uses the object referred to by the pointer, and neither
copy- nor move-construction is required. However, when using a pointer to an
object the programmer should make sure that the object's lifetime exceeds the
duration of the thread (note that this is not automatically guaranteed, as the
asynchronous task may not actually start before the future's tt(get) member is
called).
    
Because of the default tt(std::launch::deferred | std::launch::async) argument
used by the basic tt(async) call it is likely that the function which is
passed to tt(async) doesn't immediately start. The tt(launch::deferred) policy
allows the implementor to defer its execution until the program explicitly
asks for the function's results. Consider the following program:
        verbinclude(-ns4 //code examples/async2.cc)
    Although tt(async) is called in line 9, the program's output may not show
tt(fun's) output line when it is run.  This is a result of the (default) use
of tt(lauch::deferred): the system simply defers tt(fun's) execution until
requested, which doesn't happen. But the tt(future) object that's returned by
tt(async) has a member tt(wait). Once tt(wait) returns the shred state must be
available. In other words: tt(fun) must have finished. Here is what happens
when after line 9 the line tt(ret.wait()) is inserted:
        verb(
    First async call starts
        hello from fun
    First async call ends
    Second async call starts
        hello from fun
    Second async call ends
        )
    Actually, evaluation of tt(fun) can be requested at the point where we
need its results, maybe even after calling tt(asyncCall), as shown in the next
example:
        verbinclude(-ns4 //code examples/async4.cc)
    Here the tt(ret1) and tt(ret2 std::future) objects are created, but their
tt(fun) functions aren't evaluated yet. Evaluation occurs at lines 6 and 7,
resulting in the following output:
        verb(
    First async call starts
    First async call ends
    Second async call starts
    Second async call ends
        hello from fun
        hello from fun
        )    


The tt(std::async) function template is used to start a thread, making its
results available to the calling thread. On the other hand, we may only be
able to em(prepare) (package) a task (a thread), but may have to leave the
completion of the task to another thread. Scenarios like this are realized 
through objects of the class tt(std::package_task), which is the topic of the
next section.