CPP multithreading Flashcards
std::thread
Best way of using threads independently.
Works with both lamdas and functions:
void foo(int a, int b);
std: :thread t1(foo, 123, 456);
std: :thread t2([] { foo(123, 456); });
Join can be used to wait for a thread to finish
t1.join(); t2.join();
Threads are copyable, not movable, like futures.
Thread pools:
vector<thread> threadPool;</thread>
for(int i = 0; i < 10; i++)
threadPool.emplace_back([i] {safe_print(i); });
for(auto& t: threadPool)
t.join();
Mutexes
Important piece but expensive.
Several types:
- mutex
- has RAII wrapper: unique_lock
- cool, it is released upon destruction.
- example:
{ unique_lock l{m}; //or unique_lock l(m, defer_lock); and then lock(l); }
- has RAII wrapper: unique_lock
- recursive_mutex
- example:
foo(){ m.lock(); bar(); m.unlock();}
bar() {m.lock(); /*do something */ m.unlock();}
- example:
- shared_mutex
- also has RAII wrapper: shared_lock
- Avoiding deadlocks: respect the order
- if you really don’t know how to come out of it: scoped_lock (RAII)
- does fancy stuff (very slow) and makes sure there is no deadlock
- { scoped_lock l{m1, m2, m3}; … }
- does fancy stuff (very slow) and makes sure there is no deadlock
- if you really don’t know how to come out of it: scoped_lock (RAII)
Condition variables
std::condition_variable:
- wait()
- notify_one()
- notify_all()
A mutex must be held when modifying the variables that can change truth of the condition.
atomic operations
Usually much more efficient then mutexes
std::atomic<t></t>
- T load(): loads the value
- void store(T desired): stores desired object
- T exchange(T desired): stores objects and returns old value
- if integral type:
- fetch_add
- fetch_sub
- fetch_or
- fetch_xor
- fetch_and