Boost Libraries

Windows Install
Ubuntu Install C++
Ubuntu Install

boost tutorial

coroutine

With Boost.Coroutine it is possible to use coroutines in C++. Coroutines are a feature of other programming languages, which often use the keyword yield for coroutines. In these programming languages, yield can be used like return. However, when yield is used, the function remembers the location, and if the function is called again, execution continues from that location.

#include <boost/coroutine/all.hpp>
#include <iostream>

using namespace boost::coroutines;

void cooperative(coroutine<void>::push_type &sink)
{
  std::cout << "Hello";
  sink();
  std::cout << "world";
}

int main()
{
  coroutine<void>::pull_type source{cooperative};
  std::cout << ", ";
  source();
  std::cout << "!\n";
}
using namespace boost::coroutines;
void cooperative(coroutine<int>::push_type &sink)
{
    int i=0;
  sink(++i);
  sink(++i);
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    coroutine<int>::pull_type source{cooperative};
    qDebug()<<source.get();
    if(source){
        qDebug()<<source().get();
    }
    return a.exec();
}
//1 2
#include <boost/coroutine/all.hpp>
#include <stdexcept>
#include <iostream>

using boost::coroutines::coroutine;

void cooperative(coroutine<void>::push_type &sink)
{
  sink();
  throw std::runtime_error("error");
}

int main()
{
  coroutine<void>::pull_type source{cooperative};
  try
  {
    source();
  }
  catch (const std::runtime_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

C++ Notes

Create Vector Of Functions

std::vector<function<void()>> functions;

template<class T,class Par>
void addFun(T t,Par v){
    function<void()> lab=[t,v](){t(v);};
    functions.push_back(lab);

}

void callAllFuns(){
    for(auto& f:functions)
        f();
}

main(){
    auto labda=[](int i){qDebug()<<i;};
    auto labda2=[](QString str){qDebug()<<str;};
    addFun(labda,12);
    addFun(labda2,QStringLiteral("hello world"));
    callAllFuns();
}

template<class T,class ...Par>
void addFun(T t,Par ...v){
    qDebug()<<"add function";
    function<void()> lab=[t,v...](){t(v...);};
    functions.push_back(lab);
}
addFun<void(*)(int,int)>([](int a,int b)->void{},12,13);

literal operator

QString operator "" _P(unsigned long long v){
    qDebug()<<v;
    return QString::number(v);
}

84394_P;

template like function

template<typename TT,typename... TTT>
class Myfun;

template<typename TT,typename... TTT>
class Myfun<TT(TTT...)>
        {
public:
    Myfun(std::function<TT(TTT...)> fun,TTT&&... ttt){
        fun(std::forward<TTT>(ttt)...);
    }
};

int main(int argc,const char *const *const argv) {
    auto vfun=[](int v,int v2)->int{cout<<"we call function";return 0;};
    Myfun<int(int,int)> fun(vfun,1,2);
    return 0;
}

static global variables

Example:

//file 1
#include <stdio.h>
  
  extern double x;
   
  extern void func();
   
  int main( int argc, char* argv[] )
  {
     func();
     printf( "x = %lf\n", x );    
       /* Try to uses "static double x" */    
  }

//file 2
  #include <stdio.h>
   
  static double x;
   
   
  void func()
  {
     x = 12345;
     printf( "x = %lf\n", x ); 
       /* uses "static double x" */    
  }

When you compile these programs, you will get an error:

Explanation:

  • The static global variable x can only be access within File 2.
  • The main() function is not stored in the same file !

Specify Template

template<typename I>
class A{
    void fun();
};
template<>
class A<int>{

};
class B{
public:
    template<class T>
    void fun();
};

template <class T>
void B::fun(){
}
template <>
void B::fun<int>(){
}
template <class=int>
void B::fun(){
}

function return pointer of array

int (*fun())[3]{
    int i[][3]={{1,2,3}};
    return i;
}
int main(int argc,char *argv[])
{
    int(*(*f)())[3]=fun;
}

pointer to integer

    AA* a1=new AA();
     uintptr_t po=(uintptr_t)a1;
    qDebug()<<po<<sizeof(uintptr_t);
    AA* a3=(AA*)po;
    qDebug()<<a1<<"="<<a3;
    delete a3;

in modern c++
the memory of returned object or value is saved to use an extern of function so there is no need to call copy or move constructor

A fun(){
    A a(2);
    cout<<&a<<endl;
    return a;
}
int main(int argc,const char *argv[]){
    A a=fun();
    cout<<&a<<endl;//it have same address of object inside fun function
    return 0;
}

C++ String

A string is very similar to a std::vector
The following code snippet has the std::string name with the value RainerGrimm. I use the STL algorithm std::find_if to get the upper letter and then extract my first and last name into the variables firstName and lastName. The expression name.begin()+1 shows, that strings support random access iterators:

#include <algorithm>
#include <string>

std::string name{"RainerGrimm"};
auto strIt= std::find_if(name.begin()+1, name.end(),
                       [](char c){ return std::isupper(c); });
if (strIt != name.end()){
 firstName= std::string(name.begin(), strIt);
 lastName= std::string(strIt, name.end());
}

for multi byte string you can use basic_string

typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
typedef basic_string<char16_t> u16string;
typedef basic_string<char32_t> u32string;

create string

std::string defaultString;
std::string other{"123456789"};
std::string str1(other);                      // 123456789
std::string tmp(other);                       // 123456789
std::string str2(std::move(tmp));             // 123456789
std::string str3(other.begin(), other.end()); // 123456789
std::string str4(other, 2);                   // 3456789
std::string str5(other, 2, 5);                // 34567
std::string str6("123456789", 5);             // 12345
std::string str7(5, '1');                     // 11111
std::string str8({'1', '2', '3', '4', '5'});  // 12345
std::cout << str6.substr();                   // 12345
std::cout << str6.substr(1);                  // 2345
std::cout << str6.substr(1, 2);               // 23
MethodsDescription
str.empty()Checks if str has elements.
str.size(), str.length()Number of elements of the str.
str.capacity()Number of elements str can have without reallocation.
str.max_size()Number of elements str can maximal have.
str.resize(n)Increases str to n elements.
str.reserve(n)Reserve memory for a least n elements.
str.shrink_to_fit()Adjusts the capacity of the string to it’s size.
size and capacity
void showStringInfo(const std::string& s){
  std::cout << s << ": ";
  std::cout << s.size() << " ";
  std::cout << s.capacity() << " ";
  std::cout << s.max_size() << " ";
}

std::string str;
showStringInfo(str);  // "": 0 0 4611686018427387897

str +="12345";
showStringInfo(str);  // "12345": 5 5 4611686018427387897

str.resize(30);
showStringInfo(str);  // "12345": 30 30 4611686018427387897

str.reserve(1000);
showStringInfo(str);  // "12345": 30 1000 4611686018427387897

str.shrink_to_fit();
showStringInfo(str);  // "12345": 30 30 4611686018427387897

Elements Access

std::string str= {"0123456789"};
std::cout << str.front() << std::endl;           // 0
std::cout << str.back() << std::endl;            // 9
for (int i= 0; i <= 3; ++i){
  std::cout << "str[" << i << "]:" << str[i] << "; ";
} // str[0]: 0; str[1]: 1; str[2]: 2; str[3]: 3;

std::cout << str[10] << std::endl;               // undefined behaviour
try{
  str.at(10);
}
catch (const std::out_of_range& e){
  std::cerr << "Exception: " << e.what() << std::endl;
} // Exception: basic_string::at

std::cout << *(&str[0]+5) << std::endl;         // 5
std::cout << *(&str[5]) << std::endl;           // 5
std::cout << str[5] << std::endl;               // 5

search

str= {"dkeu84kf8k48kdj39kdj74945du942"};
std::string str2{"84"};

std::cout << str.find('8');                              // 4
std::cout << str.rfind('8');                             // 11
std::cout << str.find('8', 10);                          // 11
std::cout << str.find(str2);                             // 4
std::cout << str.rfind(str2);                            // 4
std::cout << str.find(str2, 10);                         // 18446744073709551615

str2="0123456789";

std::cout << str.find_first_of("678");                    // 4
std::cout << str.find_last_of("678");                     // 20
std::cout << str.find_first_of("678", 10);                // 11
std::cout << str.find_first_of(str2);                     // 4
std::cout << str.find_last_of(str2);                      // 29
std::cout << str.find_first_of(str2, 10);                 // 10
std::cout << str.find_first_not_of("678");                // 0
std::cout << str.find_last_not_of("678");                 // 29
std::cout << str.find_first_not_of("678", 10);            // 10
std::cout << str.find_first_not_of(str2);                 // 0
std::cout << str.find_last_not_of(str2);                  // 26
std::cout << str.find_first_not_of(str2, 10);             // 12
MethodsDescription
str= str2Assigns str2 to str.
str.assign(...)Assigns to stra new string.
str.swap(str2)Swaps str and str2.
str.pop_back()Removes the last character from str.
str.erase(...)Removes characters from str.
str.clear()Clears the str.
str.append(...)Appends characters to str.
str.push_back(s)Appends the character s to str.
str.insert(pos, ...)Inserts characters in str starting at pos.
str.replace(pos, len, ...)Replaces the len characters from str starting at pos
modifying functions
MethodDescription
std::to_string(val)Converts val into a std::string.
std::to_wstring(val)Converts val into a std::wstring.
std::stoi(str)Returns an int value.
std::stol(str)Returns a long value.
std::stoll(str)Returns a long long value.
std::stoul(str)Returns an unsigned long value.
std::stoull(str)Returns an unsigned long long value.
std::stof(str)Returns a float value.
std::stod(str)Returns a double value.
std::stold(str)Returns an long double value.
numeric converting

Regular Expression

typedef basic_regex<char> regex;
typedef basic_regex<wchar_t> wregex;

search

#include <regex>
...
using std::regex_constants::ECMAScript;
using std::regex_constants::icase;

std::string theQuestion="C++ or c++, that's the question.";
std::string regExprStr(R"(c\+\+)");

std::regex rgx(regExprStr);
std::smatch smatch;

if (std::regex_search(theQuestion, smatch, rgx)){
  std::cout << "case sensitive: " << smatch[0];       // c++
}

std::regex rgxIn(regExprStr, ECMAScript|icase);
if (std::regex_search(theQuestion, smatch, rgxIn)){
  std::cout << "case insensitive: " << smatch[0];     // C++
}
#include <regex>
...

// regular expression holder for time
std::regex crgx("([01]?[0-9]|2[0-3]):[0-5][0-9]");

// const char*
std::cmatch cmatch;

const char* ctime{"Now it is 23:10."};
if (std::regex_search(ctime, cmatch, crgx)){
  std::cout << ctime << std::endl;                   // Now it is 23:10.   
  std::cout << "Time: " << cmatch[0] << std::endl;   // Time: 23:10
}

// std::string
std::smatch smatch;

std::string stime{"Now it is 23:25."};
if (std::regex_search(stime, smatch, crgx)){
  std::cout << stime << std::endl;                   // Now it is 23:25.
  std::cout << "Time: " << smatch[0] << std::endl;   // Time: 23:25
}

// regular expression holder for time
std::wregex wrgx(L"([01]?[0-9]|2[0-3]):[0-5][0-9]");

// const wchar_t*
std::wcmatch wcmatch;

const wchar_t* wctime{L"Now it is 23:47."};
if (std::regex_search(wctime, wcmatch, wrgx)){
  std::wcout << wctime << std::endl;                 // Now it is 23:47.
  std::wcout << "Time: " << wcmatch[0] << std::endl; // Time: 23:47
}

// std::wstring
std::wsmatch wsmatch;

std::wstring  wstime{L"Now it is 00:03."};
if (std::regex_search(wstime, wsmatch, wrgx)){
  std::wcout << wstime << std::endl;                  // Now it is 00:03.
  std::wcout << "Time: " << wsmatch[0] << std::endl;  // Time: 00:03
}

    QByteArray bytes="hello world 112";
    std::regex reg("((\\s+)|([a-z]+)|(\\d+))+");
    std::match_results<QByteArray::iterator> matches;
    std::regex_search(bytes.begin(),bytes.end(),matches,reg);
    for(auto& v : matches){
        qDebug()<<v.first;
    }

match

#include <regex>
...

std::string numberRegEx(R"([-+]?([0-9]*\.[0-9]+|[0-9]+))");
std::regex rgx(numberRegEx);
const char* numChar{"2011"};

if (std::regex_match(numChar, rgx)){
  std::cout << numChar << " is a number." << std::endl;
}                                            // 2011 is a number.

const std::string numStr{"3.14159265359"};
if (std::regex_match(numStr, rgx)){
  std::cout << numStr << " is a number." << std::endl;
}                                           // 3.14159265359 is a number.

const std::vector<char> numVec{{'-', '2', '.', '7', '1', '8', '2',
                                '8', '1', '8', '2', '8'}};
if (std::regex_match(numVec.begin(), numVec.end(), rgx)){
    for (auto c: numVec){ std::cout << c ;};
    std::cout << " is a number." << std::endl;
}                                           // -2.718281828 is a number.

replace

string future{"Future"};
string unofficialName{"The unofficial name of the new C++ standard is C++0x."};

regex rgxCpp{R"(C\+\+0x)"};
string newCppName{"C++11"};
string newName{regex_replace(unofficialName, rgxCpp, newCppName)};

regex rgxOff{"unofficial"};
string makeOfficial{"official"};
string officialName{regex_replace(newName, rgxOff, makeOfficial)};

cout << officialName << endl;
                          // The official name of the new C++ standard is C++11.

filter

std::string future{"Future"};
const std::string unofficial{"unofficial, C++0x"};
const std::string official{"official, C++11"};

std::regex regValues{"(.*),(.*)"};
std::string standardText{"The $1 name of the new C++ standard is $2."};
std::string textNow= std::regex_replace(unofficial, regValues, standardText);
std::cout << textNow << std::endl;
                        // The unofficial name of the new C++ standard is C++0x.

std::smatch smatch;
if (std::regex_match(official, smatch, regValues)){
  std::cout << smatch.str();                                   // official,C++11
  std::string textFuture= smatch.format(standardText);
  std::cout << textFuture << std::endl;
}                       // The official name of the new C++ standard is C++11.

Multithreading

Atomic Data Types

C++ has a set of simple atomic data types. These are booleans, characters, numbers and pointers in many variants. They need the header <atomic>. You can define your atomic data type with the class template std::atomic, but there are serious restrictions for your type std::atomic<MyType>:

For MyType there are the following restrictions:

  • The copy assignment operator for MyType, for all base classes of MyType and all non-static members of MyType, must be trivial. Only a compiler generated copy assignment operator is trivial.
  • MyType must not have virtual methods or base classes.
  • MyType must be bitwise copyable and comparable so that the C functions memcpy or memcmp can be applied.

Atomic data types have atomic operations. For example load and store:

int cnt = 0;
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // undefined behavior

std::atomic<int> cnt{0};
auto f = [&]{cnt++;};
std::thread t1{f}, t2{f}, t3{f}; // OK

what is trivial ?

trivial type is a type whose storage is contiguous (trivially copyable) and which only supports static default initialization (trivially default constructible), either cv-qualified or not. It includes scalar typestrivial classes and arrays of any such types.

trivial class is a class (defined with class, struct or union) that is both trivially default constructible and trivially copyable, which implies that:

  • uses the implicitly defined default, copy and move constructors, copy and move assignments, and destructor.
  • has no virtual members.
  • has no non-static data members with brace- or equal- initializers.
  • its base class and non-static data members (if any) are themselves also trivial types.

is_trivial inherits from integral_constant as being either true_type or false_type, depending on whether T is a trivial type.

class A {};
class B { B() {} };
class C : B {};
class D { virtual void fn() {} };

int main() {
  std::cout << std::boolalpha;
  std::cout << "is_trivial:" << std::endl;
  std::cout << "int: " << std::is_trivial<int>::value << std::endl;
  std::cout << "A: " << std::is_trivial<A>::value << std::endl;
  std::cout << "B: " << std::is_trivial<B>::value << std::endl;
  std::cout << "C: " << std::is_trivial<C>::value << std::endl;
  std::cout << "D: " << std::is_trivial<D>::value << std::endl;
  return 0;
}
is_trivial:
int: true
A: true
B: false
C: false
D: false

Threads

A thread std::thread represents an executable unit. This executable unit, which the thread immediately starts, gets its work package as a callable unit. A callable unit can be a function, a function object or a lambda function

#include <thread>
...
using namespace std;

void helloFunction(){
  cout << "function" << endl;
}

class HelloFunctionObject {
public:
  void operator()() const {
    cout << "function object" << endl;
  }
};

thread t1(helloFunction);                      // function

HelloFunctionObject helloFunctionObject;
thread t2(helloFunctionObject);                // function object

thread t3([]{ cout << "lambda function"; });   // lambda function

The creator of a thread has to take care of the lifetime of its created thread. The executable unit of the created thread ends with the end of the callable. Either the creator is waiting until the created thread t is done (t.join()) or the creator detaches itself from the created thread: t.detach(). A thread t is joinable if no operation t.join() or t.detach() was performed on it. A joinable thread calls in its destructor the exception std::terminate, and the program terminates.

thread t1(helloFunction);                    // function

HelloFunctionObject helloFunctionObject;
thread t2(helloFunctionObject);              // function object

thread t3([]{ cout << "lambda function"; }); // lambda function

t1.join();
t2.join();
t3.join();

You can move a callable from one thread to another.

#include <thread>
...
std::thread t([]{ cout << "lambda function"; });  
std::thread t2;
t2= std::move(t);

std::thread t3([]{ cout << "lambda function"; });
t2= std::move(t3);                              // std::terminate

By performing t2= std::move(t) thread t2 has the callable of thread t. Assuming thread t2 already had a callable and is joinable the C++ runtime would call std::terminate. This happens exactly in t2= std::move(t3) because t2 neither executed t2.join() nor t2.detach() before.

std::thread is a variadic template.

void printStringCopy(string s){ cout << s; }
void printStringRef(const string& s){ cout << s; }

string s{"C++"};

thread tPerCopy([=]{ cout << s; });           // C++
thread tPerCopy2(printStringCopy, s);         // C++
tPerCopy.join();
tPerCopy2.join();

thread tPerReference([&]{ cout << s; });       // C++
thread tPerReference2(printStringRef, s);      // C++
tPerReference.join();
tPerReference2.join();
MethodDescription
t.join()Waits until thread t has finished its executable unit.
t.detach()Executes the created thread t independent of the creator.
t.joinable()Checks if thread t supports the calls join or detach.
t.get_id() andReturns the identity of the thread.
this_thread::get_id() 
thread::hardware_concurrency()Indicates the number of threads that can be run in parallel.
this_thread::sleep_until(absTime)Puts the thread t to sleep until time absTime.
this_thread::sleep_for(relTime)Puts the thread t to sleep for the duration relTime.
this_thread::yield()Offers the system to run another thread.
t.swap(t2) andSwaps the threads.
swap(t1, t2) 

You can only call t.join() or t.detach() once on a thread t. If you attempt to call these more than once you get the exception std::system_errorstd::thread::hardware_concurrency returns the number of cores or 0 if the runtime cannot determine the number. The sleep_until and sleep_for operations needs a time point or a time duration as argument.

Threads cannot be copied but can be moved. A swap operation performs a move when possible.

using std::this_thread::get_id;

std::thread::hardware_concurrency();      // 4

std::thread t1([]{ get_id(); });            // 139783038650112
std::thread t2([]{ get_id(); });            // 139783030257408
t1.get_id();                                // 139783038650112
t2.get_id();                                // 139783030257408

t1.swap(t2);

t1.get_id();                                // 139783030257408
t2.get_id();                                // 139783038650112
get_id();                                   // 140159896602432

Shared Variables

mutex

#include <mutex>
#include <thread>
...

using namespace std;

std::mutex mutexCout;

struct Worker{
  Worker(string n):name(n){};
  void operator() (){
    for (int i= 1; i <= 3; ++i){
      this_thread::sleep_for(chrono::milliseconds(200));
      mutexCout.lock();
      cout << name << ": " << "Work " << i << endl;
      mutexCout.unlock();
    }
  }
private:
  string name; 
};

thread herb= thread(Worker("Herb"));
thread andrei= thread(Worker(" Andrei"));
thread scott= thread(Worker ("    Scott"));
thread bjarne= thread(Worker("      Bjarne"));
Methodmutexrecursive_mutextimed_mutexrecursive_timed_mutexshared_timed_mutex
m.lockyesyesyesyesyes
m.unlockyesyesyesyesyes
m.try_lockyesyesyesyesyes
m.try_lock_for  yesyesyes
m.try_lock_until  yesyesyes

The std::shared_time_mutex enables it to implement reader-writer locks. The method m.try_lock_for(relTime) needs a relative time duration; the method m.try_lock_until(absTime) a absolute time point.

Deadlocks A deadlock is a state in which two or more threads are blocked because each thread waits for the release of a resource before it releases its resource.

You can get a deadlock very quickly if you forget to call m.unlock(). That happens for example in case of an exception in the function getVar().

m.lock();
sharedVar= getVar();//dont use lock inside getVar
m.unlock()

Locks You should encapsulate a mutex in a lock to release the mutex automatically. A lock is an implementation of the RAII idiom because the lock binds the lifetime of the mutex to its lifetime. C++11 has std::lock_guard for the simple and std::unique_lock for the advanced use case, respectively. Both need the header <mutex>. With C++14 C++ has a std::shared_lock which is in the combination with the mutex std::shared_time_mutex the base for reader-writer locks.

std::lock_guard supports only the simple use case. Therefore it can only bind its mutex in the constructor and release it in the destructor.

std::mutex coutMutex;

struct Worker{
  Worker(std::string n):name(n){};
  void operator() (){
    for (int i= 1; i <= 3; ++i){
      std::this_thread::sleep_for(std::chrono::milliseconds(200));
      std::lock_guard<std::mutex> myLock(coutMutex);
      std::cout << name << ": " << "Work " << i << std::endl;
    }
  }
private:
  std::string name;
};

unique_lock is a general-purpose mutex ownership wrapper allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables.

#include <mutex>
#include <thread>
#include <chrono>
 
struct Box {
    explicit Box(int num) : num_things{num} {}
 
    int num_things;
    std::mutex m;
};
 
void transfer(Box &from, Box &to, int num)
{
    // don't actually take the locks yet
    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
 
    // lock both unique_locks without deadlock
    std::lock(lock1, lock2);
 
    from.num_things -= num;
    to.num_things += num;
 
    // 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
}
 
int main()
{
    Box acc1(100);
    Box acc2(50);
 
    std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
    std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
 
    t1.join();
    t2.join();
}

Thread Local Data

By using the keyword thread_local, you have thread local data also known as thread local storage. Each thread has its copy of the data. Thread-local data behaves like static variables. They are created at their first usage, and their lifetime is bound to the lifetime of the thread.

std::mutex coutMutex;
thread_local std::string s("hello from ");

void addThreadLocal(std::string const& s2){
  s+= s2;
  std::lock_guard<std::mutex> guard(coutMutex);
  std::cout << s << std::endl;
  std::cout << "&s: " << &s << std::endl;
  std::cout << std::endl;
}

std::thread t1(addThreadLocal, "t1");
std::thread t2(addThreadLocal, "t2");
std::thread t3(addThreadLocal, "t3");
std::thread t4(addThreadLocal, "t4");

Condition Variables

Condition variables enable threads to be synchronised via messages. They need the header <condition_variable>. One thread acts as a sender, and the other as a receiver of the message. The receiver waits for the notification of the sender.

MethodDescription
cv.notify_one()Notifies a waiting thread.
cv.notify_all()Notifies all waiting threads.
cv.wait(lock, ...)Waits for the notification while holding a std::unique_lock.
cv.wait_for(lock, relTime, ...)Waits for a time duration for the notification while holding a std::unique_lock.
cv.wait_until(lock, absTime, ...)Waits until a time for the notification while holding a std::unique_lock.

Sender and receiver need a lock. In case of the sender a std::lock_guard is sufficient, because it only once calls lock and unlock. In the case of the receiver a std::unique_lock is necessary, because it typically often locks and unlocks its mutex.

// conditionVariable.cpp 
...
#include <condition_variable>
...

std::mutex mutex_;
std::condition_variable condVar;
bool dataReady= false;

void doTheWork(){
  std::cout << "Processing shared data." << std::endl;
}

void waitingForWork(){
  std::cout << "Worker: Waiting for work." << std::endl;
  std::unique_lock<std::mutex> lck(mutex_);
  condVar.wait(lck, []{ return dataReady; });//wait the notify
  doTheWork();
  std::cout << "Work done." << std::endl;
}

void setDataReady(){
  std::lock_guard<std::mutex> lck(mutex_);
  dataReady=true;
  std::cout << "Sender: Data is ready." << std::endl;
  condVar.notify_one();
}

std::thread t1(waitingForWork);
std::thread t2(setDataReady);

Tasks

In addition to threads, C++ has tasks to perform work asynchronously. Tasks need the header <future>. A task is parameterised with a work package and consists of the two associated components, a promise and a future. Both are connected via a data channel. The promise executes the work packages and puts the result in the data channel; the associated future picks up the result. Both communication endpoints can run in separate threads. What’s special is that the future can pick up the result at a later time. Therefore the calculation of the result by the promise is independent of the query of the result by the associated future.

asks behave like data channels. The promise puts its result in the data channel. The future waits for it and picks it up.

Threads are very different from tasks.

For the communication between the creator thread and the created thread, you have to use a shared variable. The task communicates via its data channel, which is implicitly protected. Therefore a task must not use a protection mechanism like a mutex.

The creator thread is waiting for its child with the join call. The future fut is using the `fut.get() call which is blocking if no result is there.

If an exception happens in the created thread, the created thread terminates and therefore the creator and the whole process. On the contrary, the promise can send the exceptions to the future, which has to handle the exception.

A promise can serve one or many futures. It can send a value, an exception or only a notification. You can use a task as a safe replacement for a condition variable.

#include <future>
#include <thread>
...

int res;
std::thread t([&]{ res= 2000+11;});
t.join();
std::cout << res << std::endl;             // 2011

auto fut= std::async([]{ return 2000+11; });
std::cout << fut.get() << std::endl;       // 2011

std::async behaves like an asynchronous function call. This function call takes a callable and its arguments. std::async is a variadic template and can, therefore, take an arbitrary number of arguments. The call of std::async returns a future object fut. That’s your handle for getting the result via fut.get(). Optionally you can specify a start policy for std::async. You can explicitly determine with the start policy if the asynchronous call should be executed in the same thread (std::launch::deferred) or in another thread (std::launch::async).

What’s special about the call auto fut= std::async(std::launch::deferred, ... ) is that the promise will not immediately be executed. The call fut.get() lazy starts the promise.Lazy and eager with std::async

#include <future>
...
using std::chrono::duration;
using std::chrono::system_clock;
using std::launch;

auto begin= system_clock::now();

auto asyncLazy= std::async(launch::deferred, []{ return system_clock::now(); });
auto asyncEager= std::async(launch::async, []{ return system_clock::now(); });
std::this_thread::sleep_for(std::chrono::seconds(1));

auto lazyStart= asyncLazy.get() - begin;
auto eagerStart= asyncEager.get() - begin;

auto lazyDuration= duration<double>(lazyStart).count();
auto eagerDuration= duration<double>(eagerStart).count();

std::cout << lazyDuration << " sec";                 // 1.00018 sec.
std::cout << eagerDuration << " sec";                // 0.00015489 sec.

The output of the program shows that the promise associated with the future asyncLazy is executed one second later than the promise associated with the future asyncEager. One second is exactly the time duration the creator is sleeping before the future asyncLazy asks for its result.

std::packaged_task enables you to build a simple wrapper for a callable, which can later be executed on a separate thread.

Therefore four steps are necessary.

std::packaged_task<int(int, int)> sumTask([](int a, int b){ return a+b; });
std::future<int> sumResult= sumTask.get_future();
sumTask(2000, 11);  
sumResult.get();
...
#include <future>
...

using namespace std;

struct SumUp{
  int operator()(int beg, int end){
    for (int i= beg; i < end; ++i ) sum += i;
    return sum;
  }
private:
  int beg;
  int end;
  int sum{0};
};

SumUp sumUp1, sumUp2;

packaged_task<int(int, int)> sumTask1(sumUp1);
packaged_task<int(int, int)> sumTask2(sumUp2);

future<int> sum1= sumTask1.get_future();
future<int> sum2= sumTask2.get_future();

deque< packaged_task<int(int, int)>> allTasks;
allTasks.push_back(move(sumTask1));
allTasks.push_back(move(sumTask2));

int begin{1};
int increment{5000};
int end= begin + increment;

while (not allTasks.empty()){
  packaged_task<int(int, int)> myTask= move(allTasks.front());
  allTasks.pop_front();
  thread sumThread(move(myTask), begin, end);
  begin= end;
  end += increment;
  sumThread.detach();
}

auto sum= sum1.get() + sum2.get();
cout << sum;                                   // 50005000

The promises (std::packaged_task) are moved into the std::deque allTasks. The program iterates in the while loop through all promises. Each promise runs in its thread and performs its addition in the background (sumThread.detach()). The result is the sum of all numbers from 0 to 100000.

The pair std::promise and std::future give the full control over the task.

MethodDescription
prom.swap(prom2) andSwaps the promises.
std::swap(prom, prom2) 
prom.get_future()Returns the future.
prom.set_value(val)Sets the value.
prom.set_exception(ex)Sets the exception.
prom.set_value_at_thread_exit(val)Stores the value and makes it ready if the promise exits.
prom.set_exception_at_thread_exit(ex)Stores the exception and makes it ready if the promise exits.
MethodDescription
fut.share()Returns a std::shared_future.
fut.get()Returns the result which can be a value or an exception.
fut.valid()Checks if the result is available. Returns after the call fut.get() false.
fut.wait()Waits for the result.
fut.wait_for(relTime)Waits for a time duration for the result.
fut.wait_until(absTime)Waits until a time for the result.

If a future fut asks more than once for the result, a std::future_error exception is thrown. The future creates a shared future by the call fut.share(). Shared future are associated with their promise and can independently ask for the result. A shared future has the same interface as a future.

Here is the usage of promise and future.

#include <future>
...

void product(std::promise<int>&& intPromise, int a, int b){
  intPromise.set_value(a*b);
}

int a= 20;
int b= 10;

std::promise<int> prodPromise;
std::future<int> prodResult= prodPromise.get_future();

std::thread prodThread(product, std::move(prodPromise), a, b);
std::cout << "20*10= " << prodResult.get();//wait intPromise.set_value 20*10= 200

The promise prodPromise is moved into a separate thread and performs its calculation. The future gets the result by prodResult.get().

A future fut can be synchronised with is associated promise by the call fut.wait(). Contrary to condition variables, you need no locks and mutexes, and spurious and lost wakeups are not possible.

// promiseFutureSynchronise.cpp
...
#include <future>
...

void doTheWork(){
 std::cout << "Processing shared data." << std::endl;
}

void waitingForWork(std::future<void>&& fut){
 std::cout << "Worker: Waiting for work." <<
 std::endl;
 fut.wait();//wait for set_value
 doTheWork();
 std::cout << "Work done." << std::endl;
}

void setDataReady(std::promise<void>&& prom){
 std::cout << "Sender: Data is ready." <<
 std::endl;
 prom.set_value();
}

std::promise<void> sendReady;
auto fut= sendReady.get_future();

std::thread t1(waitingForWork, std::move(fut));
std::thread t2(setDataReady, std::move(sendReady));

The call of the promise prom.set_value() wakes up the future which then can perform its work

Chrono in C++

Chrono library is used to deal with date and time. This library was designed to deal with the fact that timers and clocks might be different on different systems and thus to improve over time in terms of precision. The unique thing about chrono is that it provides a precision-neutral concept by separating duration and point of time (“timepoint”) from specific clocks.

chrono is the name of a header and also of a sub-namespace: All the elements in this header (except for the common_type specializations) are not defined directly under the std namespace (like most of the standard library) but under the std::chrono namespace.
The elements in this header deal with time. This is done mainly by means of three concepts:

Duration

std::chrono::nanoseconds
std::chrono::microseconds

using namespace std::chrono;
using namespace std;
template <typename T>
void duration_int(duration<long long,T> d){
    qDebug()<<d.count();
}

template <typename T>
void duration_float(duration<float,T> d){
    qDebug()<<d.count();
}
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    duration_int(100ms);//T=std::milli == std::chrono::milliseconds
    duration_int(345us);//T=std::micro ==std::chrono::microseconds
    duration_int(5ns);//T=std::nano =std::chrono::nanoseconds
    duration_int(345s);//std::chrono::seconds
    duration_int(35h);//T=ratio<3600> =std::chrono::hours

    duration_float<std::ratio<60,10>>(6500s);//minutes*10 (6500/60)*10=1083.333

    return app.exec();
}
constexpr auto year = 31556952ll; // seconds in average Gregorian year
 
int main()
{
    using shakes = std::chrono::duration<int, std::ratio<1, 100000000>>;
    using jiffies = std::chrono::duration<int, std::centi>;
    using microfortnights = std::chrono::duration<float, std::ratio<14*24*60*60, 1000000>>;
    using nanocenturies = std::chrono::duration<float, std::ratio<100*year, 1000000000>>;
 
    std::chrono::seconds sec(1);
 
    std::cout << "1 second is:\n";
 
    // integer scale conversion with no precision loss: no cast
    std::cout << std::chrono::microseconds(sec).count() << " microseconds\n"
              << shakes(sec).count() << " shakes\n"
              << jiffies(sec).count() << " jiffies\n";
 
    // integer scale conversion with precision loss: requires a cast
    std::cout << std::chrono::duration_cast<std::chrono::minutes>(sec).count()
              << " minutes\n";
 
    // floating-point scale conversion: no cast
    std::cout << microfortnights(sec).count() << " microfortnights\n"
              << nanocenturies(sec).count() << " nanocenturies\n";
}

Clock

A clock consists of a starting point (or epoch) and a tick rate. For example, a clock may have an epoch of February 22, 1996 and tick every second. C++ defines three clock types:

  • system_clock-It is the current time according to the system (regular clock which we see on the toolbar of the computer). It is written as- std::chrono::system_clock
  • steady_clock-It is a monotonic clock that will never be adjusted.It goes at a uniform rate. It is written as- std::chrono::steady_clock
  • high_resolution_clock– It provides the smallest possible tick period. It is written as-std::chrono::high_resolution_clock
now[static]returns a std::chrono::time_point representing the current point in time
(for all three types)
to_time_t[static]converts a system clock time point to std::time_t
(system_clock)
from_time_t[static]converts std::time_t to a system clock time point
(system_clock)
#include <iostream> 
#include <chrono> 
#include <ctime> 
  
// Function to calculate 
// Fibonacci series 
long fibonacci(unsigned n) 
{ 
    if (n < 2) return n; 
    return fibonacci(n-1) + fibonacci(n-2); 
} 
  
int main() 
{ 
    // Using time point and system_clock 
    std::chrono::time_point<std::chrono::system_clock> start, end; 
  
    start = std::chrono::system_clock::now(); 
    std::cout << "f(42) = " << fibonacci(42) << '\n'; 
    end = std::chrono::system_clock::now(); 
  
    std::chrono::duration<double> elapsed_seconds = end - start; 
    std::time_t end_time = std::chrono::system_clock::to_time_t(end); 
  
    std::cout << "finished computation at " << std::ctime(&end_time) 
              << "elapsed time: " << elapsed_seconds.count() << "s\n";
}
auto start = std::chrono::high_resolution_clock::now();
...
auto elapsed = std::chrono::high_resolution_clock::now() - start;
long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t t_c = std::chrono::system_clock::to_time_t(now - std::chrono::hours(24));
std::cout << "24 hours ago, the time was "
          << std::put_time(std::localtime(&t_c), "%F %T") << '\n';
 
std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
std::cout << "Hello World\n";
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "Printing took "
          << std::chrono::duration_cast<std::chrono::microseconds>(end - start).count()
          << "us.\n";

Permutation And Numeric Algorithms

Permutations

std::prev_permutation and std::next_permutation return the previous smaller or next bigger permutation of the newly ordered range. If a smaller or bigger permutation is not available, the algorithms return false. Both algorithms need bidirectional iterators. Per default the predefined sorting criterion std::less is used. If you use your sorting criterion, it has to obey the strict weak ordering. If not, the program is undefined.

std::vector<int> myInts{1, 2, 3};
do{
  for (auto i: myInts) std::cout << i;
  std::cout << " ";
} while(std::next_permutation(myInts.begin(), myInts.end())); 
                                    // 123 132 213 231 312 321 

std::reverse(myInts.begin(), myInts.end());
do{
  for (auto i: myInts) std::cout << i;
  std::cout << " ";
} while(std::prev_permutation(myInts.begin(), myInts.end()));
                                    // 321 312 231 213 132 123

Min and Max

You can determine the minimum, the maximum and the minimum and maximum pair of a range with the algorithms std::min_elementstd::max_element and std::minmax_element. Each algorithm can be configured with a binary predicate.

int toInt(const std::string& s){
  std::stringstream buff;
  buff.str("");
  buff << s;
  int value;
  buff >> value;
  return value;
}

std::vector<std::string> myStrings{"94", "5", "39", "-4", "-49", "1001", "-77",
                                   "23", "0", "84", "59", "96", "6", "-94"};
auto str= std::minmax_element(myStrings.begin(), myStrings.end());
std::cout << *str.first << ":" << *str.second;              // -4:96

auto asInt= std::minmax_element(myStrings.begin(), myStrings.end(),
            [](std::string a, std::string b){ return toInt(a) < toInt(b); });
std::cout << *asInt.first << ":" << *asInt.second;          // -94:1001

Numeric

std::accumulate without callable uses the following strategy

result = init;
result += *(first+0);
result += *(first+1);
...

std::adjacent_difference without callable uses the following strategy:

*(result) = *first;
*(result+1) = *(first+1) - *(first);
*(result+2) = *(first+2) - *(first+1);
...

std::partial_sum without callable uses the following strategy:

*(result) = *first;
*(result+1) = *first + *(first+1);
*(result+2) = *first + *(first+1) + *(first+2)
...
std::array<int, 9> arr{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::cout << std::accumulate(arr.begin(), arr.end(), 0);               // 45
std::cout << std::accumulate(arr.begin(), arr.end(), 1,
                             [](int a, int b){ return a*b; } );        // 362880
							 
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> myVec;
std::adjacent_difference(vec.begin(), vec.end(),
                 std::back_inserter(myVec), [](int a, int b){ return a*b; });
for (auto v: myVec) std::cout << v << " ";            // 1 2 6 12 20 30 42 56 72
std::cout << std::inner_product(vec.begin(), vec.end(), arr.begin(), 0);  // 285

myVec= {};
std::partial_sum(vec.begin(), vec.end(), std::back_inserter(myVec));
for (auto v: myVec) std::cout << v << " ";            // 1 3 6 10 15 21 28 36 45

std::vector<int> myLongVec(10);
std::iota(myLongVec.begin(), myLongVec.end(), 2000);
for (auto v: myLongVec) std::cout << v << " ";    
                            // 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009