C++ 多线程编程mutex

xiaoxiao2021-02-28  47

Mutexes: mutex recursive_mutex timed_mutex recursive_timed_mutex Locks: lock_guard unique_lock Other types: once_flag adopt_lock_t defer_lock_t try_to_lock_t Functions: try_lock lock call_once

mutex:

(constructor) Construct mutex (public member function ) lock Lock mutex (public member function ) try_lock Lock mutex if not locked (public member function ) unlock Unlock mutex (public member function ) native_handle Get native handle (public member function )

std::mutex mtx; //声明锁 mtx.lock(); //上锁 ....保护代码 mtx.unlock(); //解锁 if(mtx.try_lock()) // if currently not locked: { //如果没上锁,运行if体 ..... } mtx.unlock();

mutex example:

// mutex example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex std::mutex mtx; // mutex for critical section void print_block (int n, char c) { // critical section (exclusive access to std::cout signaled by locking mtx): mtx.lock(); for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n'; mtx.unlock(); } int main () { std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0; }

mutex::try_lock example:

// mutex::try_lock example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex volatile int counter (0); // non-atomic counter std::mutex mtx; // locks access to counter void attempt_10k_increases () { for (int i=0; i<10000; ++i) { if (mtx.try_lock()) { // only increase if currently not locked: ++counter; mtx.unlock(); } } } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(attempt_10k_increases); for (auto& th : threads) th.join(); std::cout << counter << " successful increases of the counter.\n"; return 0; }

lock_guard:

(constructor) Construct lock_guard (public member function ) (destructor) Destroy lock_guard (unlocking mutex) (public member function )

Lock guard A lock guard is an object that manages a mutex object by keeping it always locked.

On construction, the mutex object is locked by the calling thread, and on destruction, the mutex is unlocked. It is the simplest lock, and is specially useful as an object with automatic duration that lasts until the end of its context. In this way, it guarantees the mutex object is properly unlocked in case an exception is thrown.

Note though that the lock_guard object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the lock_guard that locks it.

// lock_guard example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::lock_guard #include <stdexcept> // std::logic_error std::mutex mtx; void print_even (int x) { if (x%2==0) std::cout << x << " is even\n"; else throw (std::logic_error("not even")); } void print_thread_id (int id) { try { // using a local lock_guard to lock mtx guarantees unlocking on destruction / exception: std::lock_guard<std::mutex> lck (mtx); print_even(id); } catch (std::logic_error&) { std::cout << "[exception caught]\n"; } } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_thread_id,i+1); for (auto& th : threads) th.join(); return 0; }

unique_lock:

template <class Mutex> class unique_lock; Unique lock A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked. On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible. The object supports both states: locked and unlocked. This class guarantees an unlocked status on destruction (even if not called explicitly). Therefore it is especially useful as an object with automatic duration, as it guarantees the mutex object is properly unlocked in case an exception is thrown. Note though, that the unique_lock object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the unique_lock that manages it.

unique_lock example:

// unique_lock example #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock std::mutex mtx; // mutex for critical section void print_block (int n, char c) { // critical section (exclusive access to std::cout signaled by lifetime of lck): std::unique_lock<std::mutex> lck (mtx); for (int i=0; i<n; ++i) { std::cout << c; } std::cout << '\n'; } int main () { std::thread th1 (print_block,50,'*'); std::thread th2 (print_block,50,'$'); th1.join(); th2.join(); return 0; }

unique_lock::lock/unlock

// unique_lock::lock/unlock #include <iostream> // std::cout #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock, std::defer_lock std::mutex mtx; // mutex for critical section void print_thread_id (int id) { std::unique_lock<std::mutex> lck (mtx,std::defer_lock); // critical section (exclusive access to std::cout signaled by locking lck): lck.lock(); std::cout << "thread #" << id << '\n'; lck.unlock(); } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(print_thread_id,i+1); for (auto& th : threads) th.join(); return 0; }

unique_lock::try_lock

// unique_lock::try_lock example #include <iostream> // std::cout #include <vector> // std::vector #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock, std::defer_lock std::mutex mtx; // mutex for critical section void print_star () { std::unique_lock<std::mutex> lck(mtx,std::defer_lock); // print '*' if successfully locked, 'x' otherwise: if (lck.try_lock()) std::cout << '*'; else std::cout << 'x'; } int main () { std::vector<std::thread> threads; for (int i=0; i<500; ++i) threads.emplace_back(print_star); for (auto& x: threads) x.join(); return 0; }

unique_lock::try_lock_for

// unique_lock::try_lock_for example #include <iostream> // std::cout #include <chrono> // std::chrono::milliseconds #include <thread> // std::thread #include <mutex> // std::timed_mutex, std::unique_lock, std::defer_lock std::timed_mutex mtx; void fireworks () { std::unique_lock<std::timed_mutex> lck(mtx,std::defer_lock); // waiting to get a lock: each thread prints "-" every 200ms: while (!lck.try_lock_for(std::chrono::milliseconds(200))) { std::cout << "-"; } // got a lock! - wait for 1s, then this thread prints "*" std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout << "*\n"; } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(fireworks); for (auto& th : threads) th.join(); return 0; }

unique_lock::release

// unique_lock::release example #include <iostream> // std::cout #include <vector> // std::vector #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock std::mutex mtx; int count = 0; void print_count_and_unlock (std::mutex* p_mtx) { std::cout << "count: " << count << '\n'; p_mtx->unlock(); } void task() { std::unique_lock<std::mutex> lck(mtx); ++count; print_count_and_unlock(lck.release()); } int main () { std::vector<std::thread> threads; for (int i=0; i<10; ++i) threads.emplace_back(task); for (auto& x: threads) x.join(); return 0; }

unique_lock::operator

// unique_lock::operator= example #include <iostream> // std::cout #include <vector> // std::vector #include <thread> // std::thread #include <mutex> // std::mutex, std::unique_lock, std::try_to_lock std::mutex mtx; // mutex for critical section void print_star () { std::unique_lock<std::mutex> lck(mtx,std::try_to_lock); // print '*' if successfully locked, 'x' otherwise: if (lck.owns_lock()) std::cout << '*'; else std::cout << 'x'; } int main () { std::vector<std::thread> threads; for (int i=0; i<500; ++i) threads.emplace_back(print_star); for (auto& x: threads) x.join(); return 0; }

call_once

// call_once example #include <iostream> // std::cout #include <thread> // std::thread, std::this_thread::sleep_for #include <chrono> // std::chrono::milliseconds #include <mutex> // std::call_once, std::once_flag int winner; void set_winner (int x) { winner = x; } std::once_flag winner_flag; void wait_1000ms (int id) { // count to 1000, waiting 1ms between increments: for (int i=0; i<1000; ++i) std::this_thread::sleep_for(std::chrono::milliseconds(1)); // claim to be the winner (only the first such call is executed): std::call_once (winner_flag,set_winner,id); } int main () { std::thread threads[10]; // spawn 10 threads: for (int i=0; i<10; ++i) threads[i] = std::thread(wait_1000ms,i+1); std::cout << "waiting for the first among 10 threads to count 1000 ms...\n"; for (auto& th : threads) th.join(); std::cout << "winner thread: " << winner << '\n'; return 0; }
转载请注明原文地址: https://www.6miu.com/read-2624381.html

最新回复(0)