@zhengyuhong
2015-06-08T06:59:35.000000Z
字数 13269
阅读 1272
C++11 STL Boost
constexpr mutex() noexcept;mutex (const mutex&) = delete;
void lock();
Lock mutex
The calling thread locks the mutex, blocking if necessary:
All lock and unlock operations on the mutex follow a single total order, with all visible effects synchronized between the lock operations and previous unlock operations on the same object.
The non-member function lock allows to lock more than one mutex object simultaneously, avoiding the potential deadlocks that can happen when multiple threads lock/unlock individual mutex objects in different orders.
#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutexstd::mutex mtx; // mutex for critical sectionvoid print_thread_id (int id) {// critical section (exclusive access to std::cout signaled by locking mtx):mtx.lock();std::cout << "thread #" << id << '\n';mtx.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;}
bool try_lock();
Lock mutex if not locked
Attempts to lock the mutex, without blocking:
// mutex::try_lock example#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutexvolatile int counter (0); // non-atomic counterstd::mutex mtx; // locks access to countervoid 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;}
void unlock();
Unlocks the mutex, releasing ownership over it.
If other threads are currently blocked attempting to lock this same mutex, one of them acquires ownership over it and continues its execution.
constexpr recursive_mutex() noexcept;recursive_mutex (const recursive_mutex&) = delete;
void lock();
Lock recursive mutex
The calling thread locks the recursive_mutex, blocking if necessary:
bool try_lock() noexcept;
Attempts to lock the recursive_mutex, without blocking:
void unlock();
Unlocks the recursive_mutex, releasing one level of ownership over it.
If the calling thread had a single level of ownership over the recursive_mutex, it is completely unlocked: If other threads are currently blocked attempting to lock this same recursive_mutex, one of them acquires ownership over it and continues its execution.
constexpr timed_mutex() noexcept;timed_mutex (const timed_mutex&) = delete;
void lock();
Lock timed mutex
The calling thread locks the timed_mutex, blocking if necessary (it behaves exactly as in mutex):
void unlock();
Unlock timed mutex
Unlocks the timed_mutex, releasing ownership over it (it behaves as in mutex).
bool try_lock();
Attempts to lock the timed_mutex, without blocking (it behaves exactly as in mutex):
template <class Rep, class Period>bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);
Try to lock for time span
Attempts to lock the timed_mutex, blocking for rel_time at most:
const chrono::duration<Rep,Period>& rel_time在thread中有简单实用方法,往后再新开chrono详述。try_lock_for意思是尝试在rel_time时间段内获得锁,并处于阻塞状态,一旦获得锁、或者已经过去rel_time时间段,则唤醒,并返回false,就像mutex::try_lock是立马去尝试获取锁,失败则返回,而try_lock_for则在整个时间段都尝试获取,超时返回false,超时前获取到锁返回true
template <class Clock, class Duration>bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);
在时间点前一直在尝试获取锁,成功获取到返回true,超时返回false,并在时间点前获取到锁前都是出于阻塞状态。
方便线程对互斥量上锁,但提供了更好的上锁和解锁控制
unique_lock() noexcept;explicit unique_lock (mutex_type& m);//locks it (blocking, if necessary) by calling m.lock().unique_lock (mutex_type& m, try_to_lock_t tag);//attempts to lock it (without blocking) by calling m.try_lock().unique_lock (mutex_type& m, defer_lock_t tag) noexcept;//manages m without locking it. m shall be a mutex object that is not currently locked by the constructing thread.unique_lock (mutex_type& m, adopt_lock_t tag);//manages m, which is a mutex object currently locked by the constructing threadtemplate <class Rep, class Period>unique_lock (mutex_type& m, const chrono::duration<Rep,Period>& rel_time);//manages m, and attempts to lock it during rel_time by calling m.try_lock_for(rel_time).template <class Clock, class Duration>unique_lock (mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);//manages m, and attempts to lock it before abs_time by calling m.try_lock_until(abs_time)unique_lock (unique_lock&& x);//转移管理所有权unique_lock (const unique_lock&) = delete;
namespace std{struct try_to_lock_t {};struct defer_lock_t {};struct adopt_lock_t {};};
void lock();void unlock();bool try_lock();template <class Rep, class Period>bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);template <class Clock, class Duration>bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);
与上面timed_mutex对应成员方法用法相同
explicit operator bool() const noexcept;
Return whether it owns a lock
// 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_lockstd::mutex mtx; // mutex for critical sectionvoid print_star () {std::unique_lock<std::mutex> lck(mtx,std::try_to_lock);// print '*' if successfully locked, 'x' otherwise:if (lck)std::cout << '*';elsestd::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;}
mutex_type* release() noexcept;
Release mutex
Returns a pointer to the managed mutex object, releasing ownership over it.
void swap (unique_lock& x) noexcept;
同样会在std::swap特例化为
template <class Mutex>void swap (unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
explicit lock_guard (mutex_type& m);//manages m, and locks it (by calling m.lock()).lock_guard (mutex_type& m, adopt_lock_t tag);//manages m, which is a mutex object currently locked by the constructing thread.lock_guard (const lock_guard&) = delete;
example
// constructing lock_guard with adopt_lock#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::lock_guard, std::adopt_lockstd::mutex mtx; // mutex for critical sectionvoid print_thread_id (int id) {mtx.lock();std::lock_guard<std::mutex> lck (mtx, std::adopt_lock);std::cout << "thread #" << id << '\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;}
~lock_guard();
the destructor calls the unlock member of the mutex object it manages.
condition_variable();condition_variable (const condition_variable&) = delete;
void wait (unique_lock<mutex>& lck);template <class Predicate>void wait (unique_lock<mutex>& lck, Predicate pred);//A callable object or function that takes no arguments and returns a value that can be evaluated as a bool.This is called repeatedly until it evaluates to true.
The execution of the current thread (which shall have locked lck's mutex) is blocked until notified.
At the moment of blocking the thread, the function automatically calls lck.unlock(), allowing other locked threads to continue.
Once notified (explicitly, by some other thread), the function unblocks and calls lck.lock(), leaving lck in the same state as when the function was called. Then the function returns (notice that this last mutex locking may block again the thread before returning).
If pred is specified (2), the function only blocks if pred returns false, and notifications can only unblock the thread when it becomes true (which is specially useful to check against spurious wake-up calls). This version (2) behaves as if implemented as:while (!pred()) wait(lck);
#include <iostream> // std::cout#include <thread> // std::thread, std::this_thread::yield#include <mutex> // std::mutex, std::unique_lock#include <condition_variable> // std::condition_variablestd::mutex mtx;std::condition_variable cv;int cargo = 0;bool shipment_available() {return cargo!=0;}void consume (int n) {for (int i=0; i<n; ++i) {std::unique_lock<std::mutex> lck(mtx);cv.wait(lck,shipment_available);// consume:std::cout << cargo << '\n';cargo=0;}}int main (){std::thread consumer_thread (consume,10);// produce 10 items when needed:for (int i=0; i<10; ++i) {while (shipment_available()) std::this_thread::yield();std::unique_lock<std::mutex> lck(mtx);cargo = i+1;cv.notify_one();}consumer_thread.join();return 0;}
template <class Rep, class Period>cv_status wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time);template <class Rep, class Period, class Predicate>bool wait_for (unique_lock<mutex>& lck,const chrono::duration<Rep,Period>& rel_time, Predicate pred);
Wait for timeout or until notified
// condition_variable::wait_for example#include <iostream> // std::cout#include <thread> // std::thread#include <chrono> // std::chrono::seconds#include <mutex> // std::mutex, std::unique_lock#include <condition_variable> // std::condition_variable, std::cv_statusstd::condition_variable cv;int value;void read_value() {std::cin >> value;cv.notify_one();}int main (){std::cout << "Please, enter an integer (I'll be printing dots): ";std::thread th (read_value);std::mutex mtx;std::unique_lock<std::mutex> lck(mtx);while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {std::cout << '.';}std::cout << "You entered: " << value << '\n';th.join();return 0;}
template <class Clock, class Duration>cv_status wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time);template <class Clock, class Duration, class Predicate>bool wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred);
Wait until notified or time point
void notify_one() noexcept;
Notify one
Unblocks one of the threads currently waiting for this condition.
If no threads are waiting, the function does nothing.
If more than one, it is unspecified which of the threads is selected.
// condition_variable::notify_one#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutex, std::unique_lock#include <condition_variable> // std::condition_variablestd::mutex mtx;std::condition_variable produce,consume;int cargo = 0; // shared value by producers and consumersvoid consumer () {std::unique_lock<std::mutex> lck(mtx);while (cargo==0) consume.wait(lck);std::cout << cargo << '\n';cargo=0;produce.notify_one();}void producer (int id) {std::unique_lock<std::mutex> lck(mtx);while (cargo!=0) produce.wait(lck);cargo = id;consume.notify_one();}int main (){std::thread consumers[10],producers[10];// spawn 10 consumers and 10 producers:for (int i=0; i<10; ++i) {consumers[i] = std::thread(consumer);producers[i] = std::thread(producer,i+1);}// join them back:for (int i=0; i<10; ++i) {producers[i].join();consumers[i].join();}return 0;}
void notify_all() noexcept;
Notify all
Unblocks all threads currently waiting for this condition.
If no threads are waiting, the function does nothing.
与notify_one一致,只是一次性唤醒所谓阻塞等待的线程,被唤醒的线程还需要去竞争获取锁才能真正唤醒,否则又在竞争锁过程中阻塞自己。
namespace std {enum class cv_status { no_timeout, timeout };};