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
|
The 98 bf(C++) standard did not acknowledge the existence of
multi-threading. Between then and the release of the current bf(C++) standard
computers have evolved to multi-core machines, and using multi-threading by
now is a real option to consider when developing software.
label(PTHREADS)
Multi-threading is an extensive and complex subject, and many
good reference texts on the subject exist. The bf(C++) multi-threading is
built upon the facilities offered by the emi(pthreads) library (cf.
i(Nichols, B), em(et al.)'s
url(Pthreads Programming)(http://oreilly.com/catalog/), O'Reilly
hi(Pthreads Programming)hi(http://oreilly.com/catalog/)). However,
in line with bf(C++)'s current-day philosophy the multi-threading
implementation offered by the language offers a high level interface to
multi-threading, and using the raw pthread building blocks is hardly ever
necessary (cf. i(Williams, A.) (2012): bf(C++ Concurrency in action),
Manning).
This chapter covers the facilities for multi-threading as supported by
bf(C++). Although the coverage aims at providing the tools and examples
allowing you to create your own multi-threaded programs, coverage necessarily
is far from complete. The topic of multi threading is too extensive for
that. The mentioned reference texts provide a good starting point for any
further study of multi threading.
A emi(thread of execution) (commonly abbreviated to a emi(thread)) is a single
flow of control within a program. It differs from a separately executed
program, as created by the bi(fork)(1) system call in the sense that threads
all run inside one program, while bf(fork)(1) creates independent copies of a
running program. Multi-threading means that multiple tasks are being executed
in parallel inside one program, and no assumptions can be made as to which
thread is running first or last, or at what moment in time. Especially when
the number of threads does not exceed the number of cores, each thread may be
active at the same time. If the number of threads exceed the number of cores,
the operating system will resort to emi(task switching), offering each thread
time slices in which it can perform its tasks. Task switching takes time, and
the law of diminishing returns applies here as well: if the number of threads
greatly exceeds the number of available cores (also called
emi(overpopulation)), then the overhead incurred may exceed the benefit of
being able to run multiple tasks in parallel.
Since all threads are running inside one single program, all threads share the
program's data and code. When the same data are accessed by multiple threads,
and at least one of the threads is modifying these data, access must be
synchronized to avoid that threads read data while these data are being
modified by other threads, and to avoid that multiple threads modify the same
data at the same time.
So how do we run a multi-threaded program in bf(C++)? Let's look at em(hello
world), the multi-threaded way:
verbinclude(-a -ans4 examples/hello.cc)
itemization(
it() At line 2 the header tt(thread) is included, informing the compiler
about the existence of the class tt(std::thread) (cf. section ref(THREAD));
it() At line 11 the tt(std::thread hi) object is created. It is provided
with the name of a function (hello) which will be called in a separate
thread. Actually, the second thread, running tt(hello), is immediately started
when a tt(std::thread) is defined this way;
it() The tt(main) function itself also represents a thread: the program's
first thread. It should wait until the second thread has finished. This
is realized in line 12, where tt(hi.join()) waits until the thread tt(hi)
has finished its job. Since there are no further statements in tt(main), the
program itself ends immediately thereafter.
it() The function tt(hello) itself, defined in lines 4 through 7, is
trivial: it simply inserts the text `tt(hello world)' into tt(cout), and
terminates, thus ending the second thread.
)
When compiling multi-threaded programs using the Gnu tt(g++) compiler the
ti(-pthread)
hi(compiler option: -pthread)hi(multi threading: -pthread)
option must be specified. At link-time the ti(libpthread) library must be
available as well.
To create a multi-threaded program defined in a source file tt(multi.cc)
the tt(g++) compiler can be called like this:
verb(
g++ --std=c++14 -pthread -Wall multi.cc
)
When several pre-compiled objects must be linked, the ti(-lpthread)
hi(linker option: -lpthread)hi(multi threading: -lpthread)
linker option should also be specified.
|