File: thread.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 (198 lines) | stat: -rw-r--r-- 9,522 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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
Multi threading in bf(C++) starts off with objects of the class
hi(thread)tt(std::thread). Each object of this class handles a separate
thread.

Before using tt(Thread) objects the tthi(thread) header file must be included.

Thread objects can be constructed in various ways:
    itemization(
    ittq(thread() noexcept)
       (The default constructor creates a tt(thread) object. As it receives no
function to execute, it does not start a separate thread of execution. It is
used, e.g., as a data member of a class, allowing class objects to start a
separate thread at some later point in time;)

    ittq(thread(thread &&tmp) noexcept)
       (The move constructor takes ownership of the thread controlled by
tt(tmp), while tt(tmp), if it runs a thread, loses control over its
thread. Following this, tt(tmp) is in its default state, and the newly created
thread is responsible for calling, e.g., tt(join).)

    ittq(explicit thread(Fun &&fun, Args &&...args))
       (This em(member template) (cf. section ref(MEMTEMP)) expects a function
(or functor) as its first argument. The function is immediately started as a
separate thread. If the function (or functor) expects arguments, then these
arguments can be passed to the tt(thread's) constructor immediately following
its first (function) argument. Additional arguments are passed with their
proper types and values to tt(fun). Following the tt(thread) object's
construction, a separately running thread of execution is started.

The notation tt(Arg &&...args) indicates that any additional arguments are
passed as is to the function. The types of the arguments that are passed to
the tt(thread) constructor and that are expected by the called function must
match: values must be values, references must be reference, r-value references
must be r-value references (or move construction must be supported). The
following example illustrates this requirement:
    verbinclude(-ans4 examples/threadargs.cc)
    itemization(
    it() At lines 43 through 45 we see a value, reference, and and r-value
reference being passed to a tt(std::thread): with 
the functions running the threads expecting matching argument types.
    
    it() Line 47 fails to compile, as a value argument doesn't match the
reference expected by tt(refArg). Note that this problem was solved in line 43
by using the tt(std::ref) function.

    it() On the other hand lines 49 and 58 compile OK, as tt(int) values and
class-types supporting move operations can be passed as values to functions
expecting r-value references. In this case notice that the functions expecting
the r-value references do not access the provided arguments (except for the
actions performed by their move constructors), but use move construction to
create temporary values or objects on which the functions operate.

    it() Lines 52 and 55 won't compile as the tt(NoMove) struct doesn't offer
a move constructor.
    )

    Be careful when passing local variables as arguments to thread objects: if
the thread continues to run when the function whose local variables are used
terminates, then the thread suddenly uses wild pointers or wild references, as
the local variables no longer exist. To prevent this from happening
(illustrated by the next example) do as follows:
        itemization(
        it() pass an anonymous copy of the local variable as argument to the
tt(thread) constructor, or

        it() call tt(join) on the thread object to ensure that the thread has
finished within the local variable's lifetime.
        )

    verbinclude(-ans4 examples/locals.cc)
    In line 18 be sure not to call tt(std::ref(text)) instead of
tt(std::string(text)).

    If the thread cannot be created a tt(std::system_error) exception is
thrown.

Since this constructor not only accepts functions but also function objects as
its first argument, a emi(local context) may be passed to the function
object's constructor. Here is an example of a thread receiving a function
object using a local context:
        verbinclude(-a examples/functorthread.cc)
        )
    )
    The class tt(std::thread) does not provide a copy constructor.

The following members are available:
    itemization(
    itt(thread &operator=(thread &&tmp) noexcept):
       quote(If the operator's left-hand side operand (lhs) is a joinable
thread, then tt(terminate) is called. Otherwise, tt(tmp) is assigned to the
operator's lhs and tt(tmp's) state is changed to the thread's default state
(i.e., tt(thread())).)

    ithtq(detach)(void detach())
       (Requires tt(joinable) (see below) to return tt(true).  The thread for
which tt(detach) is called continues to run. The (e.g., parent) thread calling
tt(detach) continues immediately beyond the tt(detach)-call.  After calling
tt(object.detach()), `tt(object)' no longer represents the (possibly still
continuing but now detached) thread of execution. It is the detached thread's
implementation's responsibility to release its resources when its execution
ends.

Since tt(detach) disconnects a thread from the running program, e.g.,
tt(main) no longer can wait for the thread's completion.  As a program
ends when tt(main) ends, its still running detached threads also stop, and
a program may not properly finish all its threads, as demonstrated by
the following example: 
            verbinclude(-a examples/threads2.cc)

    A detached thread may very well continue to run after the function that
launched it has finished. Here, too, you should be very careful not to pass
local variables to the detached thread, as their references or pointers will
be undefined once the function defining the local variables terminates:
            verbinclude(-a examples/detached.cc)
        )

    ithtq(get_id)(id get_id() const noexcept)
       (If the current object does not represent a running thread 
hi(id)tt(thread::id()) is returned. Otherwise, the thread's unique ID
(also obtainable from with the thread from tt(this_thread::get_id())) is
returned.)

    ithtq(join)(void join())
       (Requires tt(joinable) to return tt(true).  Blocks the thread calling
tt(join) until the thread for which tt(join) is called has
completed. Following its completion the object whose tt(join) member was
called no longer represents a running thread, and its tt(get_id) member will
return tt(std::thread::id()).

        This member was used in several examples shown so far. As noted: when
tt(main) ends while a joinable thread is still running, tt(terminate) is
called, aborting the program.)

    ithtq(joinable)(bool joinable() const noexcept)
       (returns tt(object.get_id() != id()), where tt(object) is the
tt(thread) object for which tt(joinable) was called.)

    ithtq(swap)(void swap(thread &other) noexcept)
       (The states of the tt(thread) object for which tt(swap) was called and
tt(other) are swapped. Note that threads may always be swapped, even when
their thread functions are currently being executed.)

    ithtq(hardware_concurrency)
        (unsigned thread::hardware_concurrency() noexecpt)
        (This static member returns the number of threads that can run at the
same time on the current computer. On a stand-alone multi-core computer it
(probably) returns the number of cores.)
    )

    Things to note:
    itemization(
    it() When intending to define an anonymous thread it may appear not to
start, unless you immediately also call tt(join). E.g.,
            verb(
void doSomething();
int main()
{
    thread(doSomething);        // nothing happens??
    thread(doSomething).join()  // doSomething is executed??
}
            )
    This similar to the situation we encountered in section ref(UNIFORMINIT):
the first statement doesn't define an anonymous tt(thread) object at all. It
simply defines the tt(thread) object tt(doSomething). Consequently,
compilation of the second statement fails, as there is no tt(thread(thread &))
constructor. When the first statement is omitted, the tt(doSomething) function
is executed by the second statement. If the second statement is omitted, a
default constructed tt(thread) object by the name of tt(doSomething) is
defined.

    it() A thread only starts after its construction has completed. This
includes move constructions or move assignments. E.g., in a statement like
        verb(
    thread object(thread(doSomething));
        )
    the move constructor is used to transfer control from an anonymous thread
executing tt(doSomething) to the thread tt(object). Only after tt(object)'s
construction has completed tt(doSomething) is started in the separate thread.
    
    it() Exceptions thrown from the thread (e.g., by the function defining the
thread's actions) are local to the executed thread. Either they must be caught
by the executing thread (as each running thread has its own execution stack),
or they can be passed to the starting thread using a tt(packaged_task) and a
tt(future) (cf., respectively, sections ref(PACKAGE) and ref(FUTURE)).
    )

    A thread ends when the function executing a thread finishes. When a
tt(thread) object is destroyed while its thread function is still running,
tt(terminate) is called, aborting the program's end. Bad news: the destructors
of existing objects aren't called and exceptions that are thrown are left
uncaught. This happens in the following program as the thread is still active
when tt(main) ends:
        verbinclude(-a examples/terminate.cc)
    There are several ways to solve this problem. One of them is discussed in
the next section.