[关闭]
@zhengyuhong 2015-06-08T06:59:35.000000Z 字数 13269 阅读 1272

mutex

C++11 STL Boost


mutex

mutex::mutex

  1. constexpr mutex() noexcept;
  2. mutex (const mutex&) = delete;

mutex::

  1. 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.

  1. #include <iostream> // std::cout
  2. #include <thread> // std::thread
  3. #include <mutex> // std::mutex
  4. std::mutex mtx; // mutex for critical section
  5. void print_thread_id (int id) {
  6. // critical section (exclusive access to std::cout signaled by locking mtx):
  7. mtx.lock();
  8. std::cout << "thread #" << id << '\n';
  9. mtx.unlock();
  10. }
  11. int main ()
  12. {
  13. std::thread threads[10];
  14. // spawn 10 threads:
  15. for (int i=0; i<10; ++i)
  16. threads[i] = std::thread(print_thread_id,i+1);
  17. for (auto& th : threads) th.join();
  18. return 0;
  19. }

mutex::try_lock

  1. bool try_lock();

Lock mutex if not locked
Attempts to lock the mutex, without blocking:

  1. // mutex::try_lock example
  2. #include <iostream> // std::cout
  3. #include <thread> // std::thread
  4. #include <mutex> // std::mutex
  5. volatile int counter (0); // non-atomic counter
  6. std::mutex mtx; // locks access to counter
  7. void attempt_10k_increases () {
  8. for (int i=0; i<10000; ++i) {
  9. if (mtx.try_lock()) { // only increase if currently not locked:
  10. ++counter;
  11. mtx.unlock();
  12. }
  13. }
  14. }
  15. int main ()
  16. {
  17. std::thread threads[10];
  18. // spawn 10 threads:
  19. for (int i=0; i<10; ++i)
  20. threads[i] = std::thread(attempt_10k_increases);
  21. for (auto& th : threads) th.join();
  22. std::cout << counter << " successful increases of the counter.\n";
  23. return 0;
  24. }

mutx::unlock

  1. 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.

recursive_mutex

recursive_mutex::recursive_mutex

  1. constexpr recursive_mutex() noexcept;
  2. recursive_mutex (const recursive_mutex&) = delete;

recursive_mutex::lock

  1. void lock();

Lock recursive mutex
The calling thread locks the recursive_mutex, blocking if necessary:

recursive_mutex::try_lock

  1. bool try_lock() noexcept;

Attempts to lock the recursive_mutex, without blocking:

recursive_mutex::unlock

  1. 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.

timed_mutex

timed_mutex::timed_mutex

  1. constexpr timed_mutex() noexcept;
  2. timed_mutex (const timed_mutex&) = delete;

timed_mutex::lock

  1. void lock();

Lock timed mutex
The calling thread locks the timed_mutex, blocking if necessary (it behaves exactly as in mutex):

timed_mutex::unlock

  1. void unlock();

Unlock timed mutex
Unlocks the timed_mutex, releasing ownership over it (it behaves as in mutex).

timed_mutex::try_lock

  1. bool try_lock();

Attempts to lock the timed_mutex, without blocking (it behaves exactly as in mutex):

timed_mutex::try_lock_for

  1. template <class Rep, class Period>
  2. 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:

timed_mutex::try_lock_util

  1. template <class Clock, class Duration>
  2. bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);

在时间点前一直在尝试获取锁,成功获取到返回true,超时返回false,并在时间点前获取到锁前都是出于阻塞状态。

unique_lock

方便线程对互斥量上锁,但提供了更好的上锁和解锁控制

unique_lock::unique_lock

  1. unique_lock() noexcept;
  2. explicit unique_lock (mutex_type& m);
  3. //locks it (blocking, if necessary) by calling m.lock().
  4. unique_lock (mutex_type& m, try_to_lock_t tag);
  5. //attempts to lock it (without blocking) by calling m.try_lock().
  6. unique_lock (mutex_type& m, defer_lock_t tag) noexcept;
  7. //manages m without locking it. m shall be a mutex object that is not currently locked by the constructing thread.
  8. unique_lock (mutex_type& m, adopt_lock_t tag);
  9. //manages m, which is a mutex object currently locked by the constructing thread
  10. template <class Rep, class Period>
  11. unique_lock (mutex_type& m, const chrono::duration<Rep,Period>& rel_time);
  12. //manages m, and attempts to lock it during rel_time by calling m.try_lock_for(rel_time).
  13. template <class Clock, class Duration>
  14. unique_lock (mutex_type& m, const chrono::time_point<Clock,Duration>& abs_time);
  15. //manages m, and attempts to lock it before abs_time by calling m.try_lock_until(abs_time)
  16. unique_lock (unique_lock&& x);
  17. //转移管理所有权
  18. unique_lock (const unique_lock&) = delete;
  1. namespace std{
  2. struct try_to_lock_t {};
  3. struct defer_lock_t {};
  4. struct adopt_lock_t {};
  5. };

unique_lock::public member function

  1. void lock();
  2. void unlock();
  3. bool try_lock();
  4. template <class Rep, class Period>
  5. bool try_lock_for (const chrono::duration<Rep,Period>& rel_time);
  6. template <class Clock, class Duration>
  7. bool try_lock_until (const chrono::time_point<Clock,Duration>& abs_time);

与上面timed_mutex对应成员方法用法相同

unique_lock::operator bool()

  1. explicit operator bool() const noexcept;

Return whether it owns a lock

  1. // unique_lock::operator= example
  2. #include <iostream> // std::cout
  3. #include <vector> // std::vector
  4. #include <thread> // std::thread
  5. #include <mutex> // std::mutex, std::unique_lock, std::try_to_lock
  6. std::mutex mtx; // mutex for critical section
  7. void print_star () {
  8. std::unique_lock<std::mutex> lck(mtx,std::try_to_lock);
  9. // print '*' if successfully locked, 'x' otherwise:
  10. if (lck)
  11. std::cout << '*';
  12. else
  13. std::cout << 'x';
  14. }
  15. int main ()
  16. {
  17. std::vector<std::thread> threads;
  18. for (int i=0; i<500; ++i)
  19. threads.emplace_back(print_star);
  20. for (auto& x: threads) x.join();
  21. return 0;
  22. }

unique_lock::release

  1. mutex_type* release() noexcept;

Release mutex
Returns a pointer to the managed mutex object, releasing ownership over it.

unique_lock::swap

  1. void swap (unique_lock& x) noexcept;

同样会在std::swap特例化为

  1. template <class Mutex>
  2. void swap (unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;

lock_guard

lock_guard::lock_guard

  1. explicit lock_guard (mutex_type& m);
  2. //manages m, and locks it (by calling m.lock()).
  3. lock_guard (mutex_type& m, adopt_lock_t tag);
  4. //manages m, which is a mutex object currently locked by the constructing thread.
  5. lock_guard (const lock_guard&) = delete;

example

  1. // constructing lock_guard with adopt_lock
  2. #include <iostream> // std::cout
  3. #include <thread> // std::thread
  4. #include <mutex> // std::mutex, std::lock_guard, std::adopt_lock
  5. std::mutex mtx; // mutex for critical section
  6. void print_thread_id (int id) {
  7. mtx.lock();
  8. std::lock_guard<std::mutex> lck (mtx, std::adopt_lock);
  9. std::cout << "thread #" << id << '\n';
  10. }
  11. int main ()
  12. {
  13. std::thread threads[10];
  14. // spawn 10 threads:
  15. for (int i=0; i<10; ++i)
  16. threads[i] = std::thread(print_thread_id,i+1);
  17. for (auto& th : threads) th.join();
  18. return 0;
  19. }

lock_guard::~lock_guard()

  1. ~lock_guard();

the destructor calls the unlock member of the mutex object it manages.

condition_variable

condition_variable::condition_variable

  1. condition_variable();
  2. condition_variable (const condition_variable&) = delete;

condition_variable::wait

  1. void wait (unique_lock<mutex>& lck);
  2. template <class Predicate>
  3. void wait (unique_lock<mutex>& lck, Predicate pred);
  4. //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);

  1. #include <iostream> // std::cout
  2. #include <thread> // std::thread, std::this_thread::yield
  3. #include <mutex> // std::mutex, std::unique_lock
  4. #include <condition_variable> // std::condition_variable
  5. std::mutex mtx;
  6. std::condition_variable cv;
  7. int cargo = 0;
  8. bool shipment_available() {return cargo!=0;}
  9. void consume (int n) {
  10. for (int i=0; i<n; ++i) {
  11. std::unique_lock<std::mutex> lck(mtx);
  12. cv.wait(lck,shipment_available);
  13. // consume:
  14. std::cout << cargo << '\n';
  15. cargo=0;
  16. }
  17. }
  18. int main ()
  19. {
  20. std::thread consumer_thread (consume,10);
  21. // produce 10 items when needed:
  22. for (int i=0; i<10; ++i) {
  23. while (shipment_available()) std::this_thread::yield();
  24. std::unique_lock<std::mutex> lck(mtx);
  25. cargo = i+1;
  26. cv.notify_one();
  27. }
  28. consumer_thread.join();
  29. return 0;
  30. }

condition_variable::wait_for

  1. template <class Rep, class Period>
  2. cv_status wait_for (unique_lock<mutex>& lck, const chrono::duration<Rep,Period>& rel_time);
  3. template <class Rep, class Period, class Predicate>
  4. bool wait_for (unique_lock<mutex>& lck,const chrono::duration<Rep,Period>& rel_time, Predicate pred);

  Wait for timeout or until notified

  1. // condition_variable::wait_for example
  2. #include <iostream> // std::cout
  3. #include <thread> // std::thread
  4. #include <chrono> // std::chrono::seconds
  5. #include <mutex> // std::mutex, std::unique_lock
  6. #include <condition_variable> // std::condition_variable, std::cv_status
  7. std::condition_variable cv;
  8. int value;
  9. void read_value() {
  10. std::cin >> value;
  11. cv.notify_one();
  12. }
  13. int main ()
  14. {
  15. std::cout << "Please, enter an integer (I'll be printing dots): ";
  16. std::thread th (read_value);
  17. std::mutex mtx;
  18. std::unique_lock<std::mutex> lck(mtx);
  19. while (cv.wait_for(lck,std::chrono::seconds(1))==std::cv_status::timeout) {
  20. std::cout << '.';
  21. }
  22. std::cout << "You entered: " << value << '\n';
  23. th.join();
  24. return 0;
  25. }

condition_variable::wait_until

  1. template <class Clock, class Duration>
  2. cv_status wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time);
  3. template <class Clock, class Duration, class Predicate>
  4. bool wait_until (unique_lock<mutex>& lck, const chrono::time_point<Clock,Duration>& abs_time, Predicate pred);

  Wait until notified or time point

condition_variable::notify_one

  1. 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.

  1. // condition_variable::notify_one
  2. #include <iostream> // std::cout
  3. #include <thread> // std::thread
  4. #include <mutex> // std::mutex, std::unique_lock
  5. #include <condition_variable> // std::condition_variable
  6. std::mutex mtx;
  7. std::condition_variable produce,consume;
  8. int cargo = 0; // shared value by producers and consumers
  9. void consumer () {
  10. std::unique_lock<std::mutex> lck(mtx);
  11. while (cargo==0) consume.wait(lck);
  12. std::cout << cargo << '\n';
  13. cargo=0;
  14. produce.notify_one();
  15. }
  16. void producer (int id) {
  17. std::unique_lock<std::mutex> lck(mtx);
  18. while (cargo!=0) produce.wait(lck);
  19. cargo = id;
  20. consume.notify_one();
  21. }
  22. int main ()
  23. {
  24. std::thread consumers[10],producers[10];
  25. // spawn 10 consumers and 10 producers:
  26. for (int i=0; i<10; ++i) {
  27. consumers[i] = std::thread(consumer);
  28. producers[i] = std::thread(producer,i+1);
  29. }
  30. // join them back:
  31. for (int i=0; i<10; ++i) {
  32. producers[i].join();
  33. consumers[i].join();
  34. }
  35. return 0;
  36. }

condition_variable::notify_all

  1. 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一致,只是一次性唤醒所谓阻塞等待的线程,被唤醒的线程还需要去竞争获取锁才能真正唤醒,否则又在竞争锁过程中阻塞自己。

cv_status

  1. namespace std {
  2. enum class cv_status { no_timeout, timeout };
  3. };
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注