Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 9

There are issues:

the following example using namespace std is declared, but using namespace chrono
isn’t, to make explicit which elements are inside the namespace chrono. In practice using
namespace chrono will often be declared immediately after using namespace std.
#include <iostream>
#include <chrono>
#include <iomanip>
using namespace std;
struct days: public chrono::hours
{
days(size_t count)
:
chrono::hours(count * 24)
{}
};
int main()
{
// get the current time
chrono::time_point<chrono::system_clock>
timePoint{chrono::system_clock::now()};
// convert it to a std::time_t:
time_t time = chrono::system_clock::to_time_t(timePoint);
// show the time in seconds since the epoch:
cout << time << ’\n’;
// get a std::tm value:
20.1. HANDLING TIME (ABSOLUTE AND RELATIVE) 629
tm tmValue{*localtime(&time)};
// display the time:
cout << put_time(&tmValue, "current time: %c") << ’\n’;
// display the time in rfc2822 format:
cout << put_time(&tmValue, "rfs2822 format: %a, %e %b %Y %T %z")
<< ’\n’;
// modifiy ’timePoint’:
timePoint += days(7);
// convert timePoint’s value to std::time_t:
time = chrono::system_clock::to_time_t(timePoint);
// display the gmtime, directly using gmtime’s return value:
cout << put_time(gmtime(&time),
"gmtime, one week from now: %c %z") << ’\n’;
}
20.1.5.1 std::put_time format specifiers
The following tables contain all format specifiers that can be used in the format string of the
std::put_time function.
Specifiers start with %. To display a percent character write it twice: %%. In addition to the standard
escape sequences, %n can be used instead of \n, and %t can be used instead of \t.
Year specifiers
Specifier Meaning std::tm
field(s)
%Y year as a 4 digit decimal number tm_year
%EY year in an alternative representation tm_year
%y last 2 digits of year as a decimal number
(range [00,99])
tm_year
%Oy last 2 digits of year using an alternative numeric
system
tm_year
%Ey year as offset from locale’s alternative calendar
period %EC (locale-dependent)
tm_year
%C first 2 digits of year as a decimal number
(range [00,99])
tm_year
%EC name of the base year (period) in the locale’s
alternative representation
tm_year
%G ISO 8601 week-based year, i.e. the year that
contains the specified week
tm_year,
tm_wday,
tm_yday
%g last 2 digits of ISO 8601 week-based year
(range [00,99])
tm_year,
tm_wday,
tm_yday
630 CHAPTER 20. MULTI THREADING
Month specifiers
Specifier Meaning std::tm
field(s)
%b abbreviated month name, e.g. Oct tm_mon
%h synonym of b tm_mon
%B full month name, e.g. October tm_mon
%m month as a decimal number (range [01,12]) tm_mon
%Om month using an alternative numeric system tm_mon
Week specifiers
Specifier Meaning std::tm
field(s)
%U week of the year as a decimal number (Sunday
is the first day of the week) (range [00,53])
tm_year,
tm_wday,
tm_yday
%OU week of the year, as by %U, using an alternative
numeric system
tm_year,
tm_wday,
tm_yday
%W week of the year as a decimal number (Monday
is the first day of the week) (range [00,53])
tm_year,
tm_wday,
tm_yday
%OW week of the year, as by %W, using an alternative
numeric system
tm_year,
tm_wday,
tm_yday
%V ISO 8601 week of the year (range [01,53]) tm_year,
tm_wday,
tm_yday
%OV week of the year, as by %V, using an alternative
numeric system
tm_year,
tm_wday,
tm_yday
Day of the year/month specifiers
Specifier Meaning std::tm
field(s)
%j day of the year as a decimal number (range
[001,366])
tm_yday
%d day of the month as a decimal number (range
[01,31])
tm_mday
%Od zero-based day of the month using an alternative
numeric system
tm_mday
%e day of the month as a decimal number (range
[1,31])
tm_mday
%Oe one-based day of the month using an alternative
numeric system
tm_mday
20.1. HANDLING TIME (ABSOLUTE AND RELATIVE) 631
Day of the week specifiers
Specifier Meaning std::tm
field(s)
%a abbreviated weekday name, e.g. Fri tm_wday
%A full weekday name, e.g. Friday tm_wday
%w weekday as a decimal number, where Sunday
is 0 (range [0-6])
tm_wday
%Ow weekday, where Sunday is 0, using an alternative
numeric system
tm_wday
%u weekday as a decimal number, where Monday
is 1 (ISO 8601 format) (range [1-7])
tm_wday
%Ou weekday, where Monday is 1, using an alternative
numeric system
tm_wday
Hour, minute, second specifiers
Specifier Meaning std::tm
field(s)
%H hour as a decimal number, 24 hour clock
(range [00-23])
tm_hour
%OH hour from 24-hour clock using an alternative
numeric system
tm_hour
%I hour as a decimal number, 12 hour clock
(range [01,12])
tm_hour
%OI hour from 12-hour clock using the alternative
numeric system
tm_hour
%M minute as a decimal number (range [00,59]) tm_min
%OM minute using an alternative numeric system tm_min
%S second as a decimal number (range [00,60]) tm_sec
%OS second using an alternative numeric system tm_sec
632 CHAPTER 20. MULTI THREADING
Additional specifiers
Specifier Meaning std::tm
field(s)
%c standard date and time string, e.g. Sun Oct 17
04:41:13 2010
all
fields
%Ec alternative date and time string all
fields
%x localized date representation all
fields
%Ex alternative date representation all
fields
%X localized time representation all
fields
%EX alternative time representation all
fields
%D equivalent to "%m/%d/%y" tm_mon,
tm_mday,
tm_year
%F equivalent to "%Y-%m-%d" (the ISO 8601 date
format)
tm_mon,
tm_mday,
tm_year
%r localized 12-hour clock time tm_hour,
tm_min,
tm_sec
%R equivalent to "%H:%M" tm_hour,
tm_min
%T equivalent to "%H:%M:%S" (the ISO 8601 time
format)
tm_hour,
tm_min,
tm_sec
%p localized a.m. or p.m. tm_hour
%z offset from UTC in the ISO 8601 format (e.g.
-0430; no characters if time zone information
is not available)
tm_isdst
%Z time zone name or abbreviation (no characters
if time zone information is not available)
tm_isdst
20.2 Multi Threading
In C++ multi threading may be implemented at various levels of abstraction. In general the highest
level of abstraction which is available to implement a mult-threaded problem should be used. Not
so much because it’s often simpler than using lower levels of abstraction, but because higher levels
of abstraction are usually semantically closer to the original problem description, resulting in code
which is easier to understand and therefore easier to maintain. Also, high-abstraction classes also
provide exception safety and prevent the occurrence of memory leaks.
C++’s main tool for creatingmulti-threaded programs is the class std::thread, and some examples
of its use have already been shown at the beginning of this chapter.
Characteristics of individual threads can be queried fromthe std::this_thread namespace. Also,
std::this_thread offers some control over the behavior of an individual thread.
To synchronize access to shared data C++ offers mutexes (implemented by the class std::mutex)
and condition variables (implemented by the class std::condition_variable).
20.2. MULTI THREADING 633
Members of these classes may throw system_error objects (cf. section 10.9) when encountering a
low-level error condition.
20.2.1 The namespace std::this_thread
The namespace std::this_thread contains functions that are uniquely associated with the currently
running thread.
Before using the namespace this_thread the <thread> header file must be included.
Inside the std::this_thread namespace several free functions are defined, providing information
about the current thread or that can be used to control its behavior:
• thread::id this_thread::get_id() noexcept:
returns an object of type thread::id that identifies the currently active thread of
execution. For an active thread the returned id is unique in the sense that itmaps 1:1
to the currently active thread, and is not returned by any other thread. If a thread
is currently not running thread::id() is returned by the std::thread object’s
get_id member.
• void yield() noexcept:
when a thread calls this_thread::yield() the current thread is briefly suspended,
allowing other (waiting) threads to start.
• void sleep_for(chrono::duration<Rep, Period> const &relTime) noexcept:
when a thread call this_thread::sleep_for(...) it is suspended for the amount
of time that’s specified in its argument. E.g.,
std::this_thread::sleep_for(std::chrono::seconds(5));
• void sleep_until(chrono::time_point<Clock, Duration> const &absTime)
noexcept:
when a thread calls this member it is suspended until the specified absTime is in the
past. The next example has the same effect as the previous example:
// assume using namespace std
this_thread::sleep_until(chrono::system_clock().now() + chrono::seconds(5));
Conversely, the sleep_until call in the next example immediately returns:
this_thread::sleep_until(chrono::system_clock().now() - chrono::seconds(5));
20.2.2 The class std::thread
Multi threading in C++ starts off with objects of the class std::thread. Each object of this class
handles a separate thread.
Before using Thread objects the <thread> header file must be included.
Thread objects can be constructed in various ways:
• thread() noexcept:
634 CHAPTER 20. MULTI THREADING
The default constructor creates a 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;
• thread(thread &&tmp) noexcept:
The move constructor takes ownership of the thread controlled by tmp, while tmp, if
it runs a thread, loses control over its thread. Following this, tmp is in its default
state, and the newly created thread is responsible for calling, e.g., join.
• explicit thread(Fun &&fun, Args &&...args):
This member template (cf. section 22.1.3) 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 thread’s
constructor immediately following its first (function) argument. Additional arguments
are passed with their proper types and values to fun. Following the thread
object’s construction, a separately running thread of execution is started.
The notation Arg &&...args indicates that any additional arguments are passed
as is to the function. The types of the arguments that are passed to the 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:
1: #include <iostream>
2: #include <thread>
3:
4: using namespace std;
5:
6: struct NoMove
7: {
8: NoMove() = default;
9: NoMove(NoMove &&tmp) = delete;
10: };
11:
12: struct MoveOK
13: {
14: int d_value = 10;
15:
16: MoveOK() = default;
17: MoveOK(MoveOK const &) = default;
18:
19: MoveOK(MoveOK &&tmp)
20: {
21: d_value = 0;
22: cout << "MoveOK move cons.\n";
23: }
24: };
25:
26: void valueArg(int value)
27: {}
28: void refArg(int &ref)
29: {}
30: void r_refArg(int &&tmp)
31: {
20.2. MULTI THREADING 635
32: tmp = 100;
33: }
34: void r_refNoMove(NoMove &&tmp)
35: {}
36: void r_refMoveOK(MoveOK &&tmp)
37: {}
38:
39: int main()
40: {
41: int value = 0;
42:
43: std::thread(valueArg, value).join();
44: std::thread(refArg, ref(value)).join();
45: std::thread(r_refArg, move(value)).join();
46:
47: // std::thread(refArg, value);
48:
49: std::thread(r_refArg, value).join();
50: cout << "value after r_refArg: " << value << ’\n’;
51:
52: // std::thread(r_refNoMove, NoMove());
53:
54: NoMove noMove;
55: // std::thread(r_refNoMove, noMove).join();
56:
57: MoveOK moveOK;
58: std::thread(r_refMoveOK, moveOK).join();
59: cout << moveOK.d_value << ’\n’;
60: }
– At lines 43 through 45 we see a value, reference, and and r-value reference being
passed to a std::thread: with the functions running the threads expecting
matching argument types.
– Line 47 fails to compile, as a value argument doesn’t match the reference expected
by refArg. Note that this problem was solved in line 43 by using the
std::ref function.
– On the other hand lines 49 and 58 compile OK, as 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.
– Lines 52 and 55 won’t compile as the 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:
– pass an anonymous copy of the local variable as argument to the thread constructor,
or
– call join on the thread object to ensure that the thread has finished within the
local variable’s lifetime.
1: #include <iostream>
636 CHAPTER 20. MULTI THREADING
2: #include <thread>
3: #include <string>
4: #include <chrono>
5:
6: void threadFun(std::string const &text)
7: {
8: for (size_t iter = 1; iter != 6; ++iter)
9: {
10: std::cout << text << ’\n’;
11: sstd::this_thread::sleep_for(std::chrono::seconds(1));
12: }
13: }
14:
15: std::thread safeLocal()
16: {
17: std::string text = "hello world";
18: return std::thread(threadFun, std::string(text));
19: }
20:
21: int main()
22: {
23: std::thread local(safeLocal());
24: std::cout << "safeLocal has ended\n";
25: local.join();
26: }
In line 18 be sure not to call std::ref(text) instead of std::string(text).
If the thread cannot be created a std::system_error exception is thrown.
Since this constructor not only accepts functions but also function objects as its first
argument, a 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:
#include <iostream>
#include <thread>
#include <array>
using namespace std;
class Functor
{
array<int, 30> &d_data;
int d_value;
public:
Functor(array<int, 30> &data, int value)
:
d_data(data),
d_value(value)
{}
void operator()(ostream &out)
{
for (auto &value: d_data)
{
value = d_value++;
out << value << ’ ’;
20.2. MULTI THREADING 637
}
out << ’\n’;
}
};
int main()
{
array<int, 30> data;
Functor functor(data, 5);
thread funThread(functor, ref(cout));
funThread.join();
};
The class std::thread does not provide a copy constructor.
The following members are available:
• thread &operator=(thread &&tmp) noexcept:
If the operator’s left-hand side operand (lhs) is a joinable thread, then terminate is
called. Otherwise, tmp is assigned to the operator’s lhs and tmp’s state is changed
to the thread’s default state (i.e., thread()).
• void detach():
Requires joinable (see below) to return true. The thread for which detach is
called continues to run. The (e.g., parent) thread calling detach continues immediately
beyond the detach-call. After calling object.detach(), ‘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 detach disconnects a thread from the running program, e.g., main no longer
can wait for the thread’s completion. As a program ends when 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:
#include <thread>
#include <iostream>
#include <chrono>
void fun(size_t coun

You might also like