第29课 互斥量与自解锁(std::mutex和lock系列)
一. 互斥量
(一)Mutex系列类
1. std::mutex:独占的互斥量,不能递归使用。
2. std::recursive_mutex:递归互斥量。允许同一线程多次获得该互斥锁,可以用来解决同一线程需要多次获取互斥量时死锁的问题。
3. std::time_mutex和std::recursive_time_mutex:带超时的互斥量。前者是超时的独占锁,后者为超时的递归锁。主要用于获取锁时增加超时等待功能,因为有时不知道获取锁需要多久,为了不至于一直等待下去,就设置一个等待超时时间。比std::mutex多了两个超时获取锁的接口:try_lock_for和try_lock_until
- //1. 独占互斥锁,不能递归使用
- class mutex
- {
- public:
- //std::mutex不支持copy和move操作。
- mutex(const mutex&) = delete;
- mutex& operator=(const mutex&) = delete;
- constexpr mutex() noexcept; //构造函数:新的对象是未锁的
- ~mutex();
- void lock(); //上锁
- void unlock(); //解锁
- bool try_lock(); //尝试上锁。成功,返回true。失败时返回false,但不阻塞。会有三种情况
- //(1)如果当前互斥量没被其他线程占有,则锁住互斥量,直到该线程调用unlock
- //(2)如果当前互斥量被其他线程占用,则调用线程返回false,且不会被阻塞
- //(3)如果互斥量己被当前线程锁住,则会产生死锁
- };
- //2. 递归互斥锁可以被同一个线程多次加锁(增加锁计数),以获得对互斥锁对象的多层所有权。
- //可以用来解决同一线程需要多次获取互斥量时死锁的问题
- class recursive_mutex
- {
- public :
- recursive_mutex(const recursive_mutex&) = delete;
- recursive_mutex& operator=(const recursive_mutex&) = delete;
- recursive_mutex() noexcept;
- ~recursive_mutex();
- void lock();
- void unlock(); //释放互斥量时需要调用与该锁层次深度相同次数的unlock(),即lock()次数和unlock()次数相同
- bool try_lock() noexcept;
- };
- //3. 带超时的互斥锁,不能递归使用
- class timed_mutex
- {
- public :
- timed_mutex(const timed_mutex&) = delete;
- timed_mutex& operator=(const timed_mutex&) = delete;
- timed_mutex();
- ~timed_mutex();
- void lock();
- void unlock();
- bool try_lock();
- //在指定的relative_time时间内,尝试获取*this上的锁。当relative_time.count()<=0时
- //将立即返回,就像调用try_lock()样。否则会阻塞,直到获取锁或超过给定的relative_time时间
- //当锁被调用线程获取,返回true;反之,返回false.
- template<typename Rep, typename Period>
- bool try_lock_for(const std::chrono::duration<Rep, Period>& relative_time);
- //在指定的absolute_time时间内,尝试获取*this上的锁。当absolute_time<=clock::now()时
- //将立即返回,就像调用try_lock()一样。否则会阻塞,直到获取锁或Clock::now()返回的
- //时间等于或超过给定的absolute_time的时间。返回值含义与try_lock_for相同。
- template<typename Clock, typename Duration>
- bool try_lock_until(const std::chrono::time_point<Clock, Duration>& absolute_time);
- };
- //4. 带定时的递归互斥锁
- class recursive_timed_mutex
- {
- public :
- recursive_timed_mutex(const recursive_timed_mutex&) = delete;
- recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
- recursive_timed_mutex();
- ~recursive_timed_mutex();
- void lock();
- void unlock();
- bool try_lock() noexcept;
- template<typename Rep, typename Period>
- bool try_lock_for(const std::chrono::duration<Rep, Period>& relative_time);
- template<typename Clock, typename Duration>
- bool try_lock_until(const std::chrono::time_point<Clock, Duration>& absolute_time);
- };
【Mutex系列类源码摘要】
(二)注意事项
1. lock和unlock必须成对出现,否则可能引起未定义行为。为了防止出现这种行为,可用std::lock_guard、std::unique_lock等RAII方式来使用mutex。
2. 尽量不要使用递归锁,主要原因如下:
(1)需要用到递归锁定的多线程互斥处理往往本身就可以简化,允许递归互斥很容易放纵复杂逻辑的产生,从而导致一些多线程同步引起的晦涩问题。
(2)递归锁比起非递归锁,效率会更低一些。
(3)递归锁虽然允许同一线程多次获得同一个互斥量,可重复获得最大次数并未具体说明,一旦超过一定次数,再对lock进行调用就会抛出std::system错误。
3. 互斥量不允许拷贝,也不允许移动。新创建的互斥量对象是未上锁的。
4. 多线程中,对多个互斥量须遵循同样的顺序进行加锁,否则可能会产生死锁现象。
【编程实验】mutex系列
- #include <iostream>
- #include <mutex>
- #include <thread>
- #include <chrono>
- #include <list>
- //1. 独占互斥量
- std::mutex g_mtx;
- int tickets = ;
- //1.1 多线程模拟火车站多窗口售票
- void sell_ticket()
- {
- while (true) {
- g_mtx.lock();
- if (tickets > ) {
- std::cout << "thread id(" << std::this_thread::get_id() << ") sell ticket: " << - tickets-- << std::endl;
- }
- else {
- g_mtx.unlock();
- break;
- }
- g_mtx.unlock();
- std::this_thread::sleep_for(std::chrono::milliseconds());
- }
- }
- //1.2 消息处理系统
- class MsgManage
- {
- std::mutex mtx;
- std::list<int> lst;
- public:
- MsgManage(){}
- ~MsgManage() {}
- void InMsg()
- {
- for (int i = ; i < ; ++i)
- {
- mtx.lock();
- std::cout << "insert element: " << i << std::endl;
- lst.push_back(i);
- mtx.unlock();
- std::this_thread::sleep_for(std::chrono::milliseconds());
- }
- }
- void outMsg()
- {
- while (true)
- {
- int num = ;
- mtx.lock();
- if (!lst.empty()) {
- num = lst.front();
- lst.pop_front();
- std::cout << "remove element: " << num << std::endl;
- }else {
- std::cout << "message queue is empty!" << std::endl;
- }
- if (num == ) { mtx.unlock(); break;}
- mtx.unlock();
- std::this_thread::sleep_for(std::chrono::milliseconds());
- }
- }
- };
- //2. 递归互斥量
- struct Complex
- {
- std::recursive_mutex rmtx;
- int i;
- Complex(int i):i(i){}
- void mul(int x)
- {
- rmtx.lock();
- i *= x;
- rmtx.unlock();
- }
- void div(int x)
- {
- rmtx.lock();
- i /= x;
- rmtx.unlock();
- }
- void both(int x, int y)
- {
- rmtx.lock();
- mul(x); //递归,会使得同一线程两次获取互斥量
- div(y);
- rmtx.unlock();
- }
- };
- //3. 带有超时的互斥量
- std::timed_mutex tmutex;
- void work()
- {
- std::chrono::microseconds timeout();
- while (true) {
- if (tmutex.try_lock_for(timeout)) {
- std::cout << std::this_thread::get_id() << ": do work with this mutex" << std::endl;
- std::chrono::microseconds sleepDuration();
- std::this_thread::sleep_for(sleepDuration);
- tmutex.unlock();
- }else {
- std::cout << std::this_thread::get_id() << ": do work without mutex" << std::endl;
- std::chrono::microseconds sleepDuration();
- std::this_thread::sleep_for(sleepDuration);
- }
- }
- }
- using namespace std;
- int main()
- {
- //1. 独占互斥量
- std::thread ths[];
- for (int i = ; i < ; ++i) {
- ths[i] = std::thread(sell_ticket);
- }
- for (auto& th : ths)
- {
- th.join();
- }
- MsgManage manage;
- std::thread outMsg(&MsgManage::outMsg, &manage);
- std::thread inMsg(&MsgManage::InMsg, &manage);
- inMsg.join();
- outMsg.join();
- //2. 递归互斥量
- Complex cmpl();
- cmpl.both(, );
- //3. 带超时的互斥量
- std::thread t1(work);
- std::thread t2(work);
- t1.join();
- t2.join();
- return ;
- }
二. 自解锁
(一)std::lock_guard
- //空的标记类
- struct adopt_lock_t {};
- //常量对象
- constexpr adopt_lock_t adopt_lock {};
- // CLASS TEMPLATE lock_guard
- template <class _Mutex>
- class lock_guard { //利用析构函数解锁互斥量
- public:
- using mutex_type = _Mutex;
- explicit lock_guard(_Mutex& _Mtx) : _MyMutex(_Mtx) { //构造,并加锁
- _MyMutex.lock();
- }
- lock_guard(_Mutex& _Mtx, adopt_lock_t) : _MyMutex(_Mtx) { //构造,但不加锁
- }
- ~lock_guard() noexcept { // unlock
- _MyMutex.unlock();
- }
- lock_guard(const lock_guard&) = delete;
- lock_guard& operator=(const lock_guard&) = delete;
- private:
- _Mutex& _MyMutex;
- };
【std::lock_guard源码摘要】
1. 利用RAII技术在析构函数中对Mutex自动解锁。但要注意,lock_guard并不负责管理Mutex的生命期。在lock_gurad对象的生命周期内,它所管理的Mutex对象会一直保持上锁状态,直至生命周期结束后才被解锁。不需要,也无法手动通过lock_gurad对Mutex进行上锁和解锁操作。从总体上而言,没有给程序员提供足够的灵活度来对互斥量的进行上锁和解锁控制。
2. 它有两个重载的构造函数,其中lock_gurad(_Mutex&)会自动对_Mutex进行加锁,而lock_gurad(_Mutex&,adopt_lock_t)则只构造但不加锁,因此需要在某个时候通过调用_Mutex本身的lock()进行上锁 (说明:adopt_lock_t是个空的标签类,起到通过标签来重载构造函数的作用)。
3.模板参数表示互斥量类型。如std::mutex、std::recursive_mutex、std::timed_mutex,std::recursive_timed_mutex等。这些互斥量只有几种基本操作:lock和unlock,以及try_lock系列函数。
4. lock_guard对象不可拷贝和移动。
(二)std::unique_lock
- //空的标记类
- struct adopt_lock_t {};
- struct defer_lock_t {};
- struct try_to_lock_t {};
- //常量对象
- constexpr adopt_lock_t adopt_lock {};
- constexpr defer_lock_t defer_lock {};
- constexpr try_to_lock_t try_to_lock {};
- // CLASS TEMPLATE unique_lock
- template <class _Mutex>
- class unique_lock { // 在析构函数中自动解锁mutex
- public:
- using mutex_type = _Mutex;
- // CONSTRUCT, ASSIGN, AND DESTROY
- unique_lock() noexcept : _Pmtx(nullptr), _Owns(false) { // 默认构造函数
- }
- explicit unique_lock(_Mutex& _Mtx) : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // 构造并上锁。
- _Pmtx->lock(); //如果其他unique_lock己拥有该_Mtx,则会阻塞等待
- _Owns = true; //成功获取锁,拥有锁的所有权。
- }
- unique_lock(_Mutex& _Mtx, adopt_lock_t)
- : _Pmtx(_STD addressof(_Mtx)), _Owns(true) { // 构造,并假定己上锁(mutex需要在外面事先被锁住)。注意拥有锁的所有权
- }
- unique_lock(_Mutex& _Mtx, defer_lock_t) noexcept
- : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // 构造,但不上锁。false表示并未取得锁的所有权。
- }
- unique_lock(_Mutex& _Mtx, try_to_lock_t)
- : _Pmtx(_STD addressof(_Mtx)), _Owns(_Pmtx->try_lock()) { // 构造,并尝试上锁。如果上锁不成功,并不会阻塞当前线程
- }
- template <class _Rep, class _Period>
- unique_lock(_Mutex& _Mtx, const chrono::duration<_Rep, _Period>& _Rel_time) //在给定的时长内尝试获取锁。
- : _Pmtx(_STD addressof(_Mtx)), _Owns(_Pmtx->try_lock_for(_Rel_time)) { // construct and lock with timeout
- }
- template <class _Clock, class _Duration>
- unique_lock(_Mutex& _Mtx, const chrono::time_point<_Clock, _Duration>& _Abs_time) //在给定的时间点内尝试获取锁
- : _Pmtx(_STD addressof(_Mtx)), _Owns(_Pmtx->try_lock_until(_Abs_time)) { // construct and lock with timeout
- }
- unique_lock(_Mutex& _Mtx, const xtime* _Abs_time)
- : _Pmtx(_STD addressof(_Mtx)), _Owns(false) { // try to lock until _Abs_time
- _Owns = _Pmtx->try_lock_until(_Abs_time);
- }
- //支持移动构造
- unique_lock(unique_lock&& _Other) noexcept : _Pmtx(_Other._Pmtx), _Owns(_Other._Owns) { // 移动拷贝,destructive copy
- _Other._Pmtx = nullptr; //失去对原mutex的所有权
- _Other._Owns = false;
- }
- //支持移动赋值
- unique_lock& operator=(unique_lock&& _Other) { //移动赋值, destructive copy
- if (this != _STD addressof(_Other)) { // different, move contents
- if (_Owns) {
- _Pmtx->unlock();
- }
- _Pmtx = _Other._Pmtx;
- _Owns = _Other._Owns;
- _Other._Pmtx = nullptr;
- _Other._Owns = false;
- }
- return *this;
- }
- ~unique_lock() noexcept { // clean up
- if (_Owns) {
- _Pmtx->unlock(); //析构函数中解锁
- }
- }
- unique_lock(const unique_lock&) = delete;
- unique_lock& operator=(const unique_lock&) = delete;
- void lock() { // lock the mutex
- _Validate();
- _Pmtx->lock();
- _Owns = true;
- }
- _NODISCARD bool try_lock() { // try to lock the mutex
- _Validate();
- _Owns = _Pmtx->try_lock();
- return _Owns;
- }
- template <class _Rep, class _Period>
- _NODISCARD bool try_lock_for(const chrono::duration<_Rep, _Period>& _Rel_time) { // try to lock mutex for _Rel_time
- _Validate();
- _Owns = _Pmtx->try_lock_for(_Rel_time);
- return _Owns;
- }
- template <class _Clock, class _Duration>
- _NODISCARD bool try_lock_until(
- const chrono::time_point<_Clock, _Duration>& _Abs_time) { // try to lock mutex until _Abs_time
- _Validate();
- _Owns = _Pmtx->try_lock_until(_Abs_time);
- return _Owns;
- }
- _NODISCARD bool try_lock_until(const xtime* _Abs_time) { // try to lock the mutex until _Abs_time
- _Validate();
- _Owns = _Pmtx->try_lock_until(_Abs_time);
- return _Owns;
- }
- void unlock() { // try to unlock the mutex
- if (!_Pmtx || !_Owns) {
- _THROW(system_error(_STD make_error_code(errc::operation_not_permitted)));
- }
- _Pmtx->unlock();
- _Owns = false;
- }
- void swap(unique_lock& _Other) noexcept { // swap with _Other
- _STD swap(_Pmtx, _Other._Pmtx);
- _STD swap(_Owns, _Other._Owns);
- }
- _Mutex* release() noexcept { // 返回指向它所管理的 Mutex 对象的指针,并释放所有权
- _Mutex* _Res = _Pmtx;
- _Pmtx = nullptr;
- _Owns = false;
- return _Res;
- }
- _NODISCARD bool owns_lock() const noexcept { // 返回当前 std::unique_lock 对象是否获得了锁
- return _Owns;
- }
- explicit operator bool() const noexcept { // 返回当前 std::unique_lock 对象是否获得了锁
- return _Owns;
- }
- _NODISCARD _Mutex* mutex() const noexcept { // return pointer to managed mutex
- return _Pmtx;
- }
- private:
- _Mutex* _Pmtx;
- bool _Owns; //是否拥有锁(当mutex被lock时,为true;否则为false)
- void _Validate() const { // check if the mutex can be locked
- if (!_Pmtx) {
- _THROW(system_error(_STD make_error_code(errc::operation_not_permitted)));
- }
- if (_Owns) {
- _THROW(system_error(_STD make_error_code(errc::resource_deadlock_would_occur)));
- }
- }
- };
【std::unique_lock源码摘要】
1. 以独占所有权的方式管理Mutex对象的上锁和解锁操作,即没有其他的unique_lock对象同时拥有某个Mutex对象的所有权。同时要注意,unique_lock并不负责管理Mutex的生命期。
2. 与std::lock_guard一样,在unique_lock生命期结束后,会对其所管理的Mute进行解锁(注意:unique_lock只对拥有所有权的mutex才会在析构函数中被自动unlock)。但unique_lock比lock_guard使用更加灵活,功能更加强大
3. unique_lock模板参数的类型与lock_guard类型的含义相同。
4. unique_lock的构造函数:
(1)unique_lock()默认构造函数:新创建的unique_lock对象不管理任何Mute对象。
(2)unique_lock(_Mutex& m):构造并上锁。如果此时某个另外的unique_lock己管理m对象,则当前线程会被阻塞。
(3)unique_lock(_Mutex& m, adopt_lock_t):构造,并假定m己上锁。(m需要事先被上锁,构造结束后unique_lock就拥有m的所有权)
(4)unique_lock(_Mutex& _Mtx, defer_lock_t):构造,但不上锁。对象创建以后,可以手动调用unique_lock的lock来上锁,才拥有_Mtx的所有权(再次强调一下,只有拥有所有权的mutex才会在析构函数中被自动unlock)
(5)unique_lock(_Mutex& _Mtx, try_to_lock_t):构造,并尝试上锁。如果上锁不成功,并不会阻塞当前线程。
(6)在给定时长内或给定时间点尝试获锁,并构造unique_lock对象。
5.上锁/解锁操作:lock,try_lock,try_lock_for,try_lock_until 和 unlock
(三)std::lock和std::scoped_lock
1. void std::lock(lock0&,lock1&,…,lockN&) 函数模板:
(1)std::lock会尝试同时对多个可锁定对象加锁,它使用免死锁算法避免死锁。若任何一个不可用则阻塞。函数返回后,所有可锁定对象己全部加锁。如果期间发生异常,则该异常会被抛出,同时释放所有己获取的锁。
(2)由于std::lock是个函数模板,它会为可锁定对象加锁,但不会并自动解锁。因此需要为每个可锁定对象手工解锁,也可以用带有adopt_lock参数的std::lock_guard,或者使用defer_lock参数的unique_lock来辅助解锁操作。
2. std::scoped_lock类模板(C++17支持)
- // CLASS TEMPLATE scoped_lock
- template <class... _Mutexes>
- class scoped_lock { // class with destructor that unlocks mutexes
- public:
- explicit scoped_lock(_Mutexes&... _Mtxes) : _MyMutexes(_Mtxes...) { // construct and lock
- _STD lock(_Mtxes...);
- }
- explicit scoped_lock(adopt_lock_t, _Mutexes&... _Mtxes) : _MyMutexes(_Mtxes...) { // construct but don't lock
- }
- ~scoped_lock() noexcept { // unlock all
- _For_each_tuple_element(_MyMutexes, [](auto& _Mutex) noexcept { _Mutex.unlock(); });
- }
- scoped_lock(const scoped_lock&) = delete;
- scoped_lock& operator=(const scoped_lock&) = delete;
- private:
- tuple<_Mutexes&...> _MyMutexes;
- };
【std::scoped_lock源码摘要】
(1)是个类模板,它封装了对std::lock的操作,可以避免对多个互斥量加锁时造成的死锁现象。同时利用RAII技术,实现对象析构时自动对这些互斥量进行解锁。
(2)构造函数:
①scoped_lock(_Mutexes&... _Mtxes):构造scoped_lock,并上锁。
②scoped_lock(adopt_lock_t, _Mutexes&... _Mtxes):构造但不上锁。
(3)scoped_lock对象不可复制和移动
【编程实验】自解锁系列
- #include <iostream>
- #include <mutex>
- #include <thread>
- #include <chrono>
- #include <vector>
- using namespace std;
- //1. std::lock与std::lock_guard或std::unique_lock配合使用
- struct Box
- {
- explicit Box(int num) : num_things(num) {};
- int num_things;
- std::mutex m;
- };
- void transfer(Box& from, Box& to, int num)
- {
- //1. 方法1:使用lock_guard为多个mutex加锁
- //std::lock(from.m, to.m); //注意,这里传入的是mutex对象。(要先加锁)
- //std::lock_guard<std::mutex> lck1(from.m, std::adopt_lock); //adopt_lock:己假定from.m被上锁
- //std::lock_guard<std::mutex> lck2(to.m, std::adopt_lock);
- //2. 方法2:使用unique_lock为多个mutex加锁
- //必须使用std::defer_lock,而不是std::adopt_lock参数。因为当传入adopt_lock时,表示己假定事先己上锁,
- //就不能再为其加锁,否则会抛出异常。而std::defer_lock表示加锁操作会延迟到后续调用std::lock()时。
- std::unique_lock<std::mutex> lck1(from.m, std::defer_lock); //defer:未实际加锁
- std::unique_lock<std::mutex> lck2(to.m, std::defer_lock); //同上
- //同时锁定两个lock,而不死锁
- std::lock(lck1, lck2); //会调用lck1和lck2的lock()。注意,这里传入的是unique_lock对象
- from.num_things -= num;
- to.num_things += num;
- //from.m 与to.m的互斥解锁于unique_lock或lock_guard的析构函数
- }
- //2. 使用std::scoped_lock来锁定多个互斥量
- struct Employee
- {
- std::string id;
- std::vector<std::string> lunch_partners; //午餐合伙人
- std::mutex m;
- std::string output() const
- {
- std::string ret = "Employee " + id + " has lunch partners: ";
- for (const auto& parner : lunch_partners)
- ret += parner + " ";
- return ret;
- }
- Employee(std::string id) :id(id){}
- };
- void send_mail(Employee&, Employee&)
- {
- //模拟耗时的发信操作
- std::this_thread::sleep_for(std::chrono::seconds());
- }
- //分配午餐合伙人
- void assign_lunch_partner(Employee& e1, Employee& e2)
- {
- static std::mutex io_mutex; //用于同步std::cout/std::endl操作
- {
- std::lock_guard<std::mutex> lk(io_mutex);
- std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl;
- }
- //scoped_lock可以避免像使用std::lock/std::unique_lock那样繁琐的使用方式。
- //使用scoped_lock可同时获取两个锁,而不必担心对assign_lunch_partner的其它调用会造成死锁
- {
- std::scoped_lock lk(e1.m, e2.m);
- {
- std::lock_guard<std::mutex> lk(io_mutex);
- std::cout << e1.id << " and " << e2.id << " got locks" << std::endl;
- }
- e1.lunch_partners.push_back(e2.id);
- e2.lunch_partners.push_back(e1.id);
- }
- send_mail(e1, e2);
- send_mail(e2, e1);
- }
- int main()
- {
- //1. std::lock的使用(配合std::lock_guard或std::unique_lock使用)
- Box b1();
- Box b2();
- std::thread t1(transfer, std::ref(b1), std::ref(b2), );
- std::thread t2(transfer, std::ref(b1), std::ref(b2), );
- t1.join();
- t2.join();
- std::cout << "box 1 num = " << b1.num_things << std::endl;
- std::cout << "box 2 num = " << b2.num_things << std::endl;
- //2. scoped_lock的使用:
- Employee alice("alice"), bob("bob"), christina("christina"), dave("dave");
- //在线程中指派合伙人,因为内部的发邮件给用户操作会消耗较长时间。
- std::vector<std::thread> threads;
- threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob));
- threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob));
- threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice));
- threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob));
- for (auto& th : threads) th.join();
- std::cout << alice.output() << endl;
- std::cout << bob.output() << endl;
- std::cout << christina.output() << endl;
- std::cout << dave.output() << endl;
- return ;
- }
- /*输出结果
- box 1 num = 85
- box 2 num = 65
- alice and bob are waiting for locks
- alice and bob got locks
- christina and alice are waiting for locks
- christina and alice got locks
- christina and bob are waiting for locks
- christina and bob got locks
- dave and bob are waiting for locks
- dave and bob got locks
- Employee alice has lunch partners: bob christina
- Employee bob has lunch partners: alice christina dave
- Employee christina has lunch partners: alice bob
- Employee dave has lunch partners: bob
- */
第29课 互斥量与自解锁(std::mutex和lock系列)的更多相关文章
- posix thread互斥量
互斥量 互斥量(Mutex)是“mutual exclusion”的缩写.互斥量是实现线程同步,和保护同时写共享数据的主要方法.使用互斥量的典型顺序如下:1. 创建和初始一个互斥量 2. 多个线程尝试 ...
- Linux的线程同步对象:互斥量Mutex,读写锁,条件变量
进程是Linux资源分配的对象,Linux会为进程分配虚拟内存(4G)和文件句柄等 资源,是一个静态的概念.线程是CPU调度的对象,是一个动态的概念.一个进程之中至少包含有一个或者多个线程.这 ...
- pThreads线程(二) 线程同步--互斥量/锁
互斥量(Mutex)是“mutual exclusion”的缩写.互斥量是实现线程同步,和保护同时写共享数据的主要方法. 互斥量对共享数据的保护就像一把锁.在Pthreads中,任何时候仅有一个线程可 ...
- posix多线程--互斥量
多线程程序在线程间共享数据时,如果多个线程同时访问共享数据就可能有问题.互斥量是解决多个线程间共享数据的方法之一. 1.互斥量初始化两种方式:(1)静态初始化 #include <pthread ...
- pthread中互斥量,锁和条件变量
互斥量 #include <pthread.h> pthread_mutex_t mutex=PTHREAD_MUTEX_INTIIALIZER; int pthread_mutex_in ...
- Qt 互斥量 QMutex
QMutex类提供了一种保护一个变量和一段代码的方法. mutex.lock() //锁住互斥量(mutex).如果互斥量是解锁的,那么当前线程就立即占用并锁定它.否则,当前线程就会被阻塞,知道掌握这 ...
- Cocos2d-X多线程(2) 线程的互斥量std::mutex和线程锁
多个线程同时访问共享资源时,经常会出现冲突等.为了避免这种情况的发生,可以使用互斥量,当一个线程锁住了互斥量后,其他线程必须等待这个互斥量解锁后才能访问它. thread提供了四种不同的互斥量: 1. ...
- 互斥量mutex简介
互斥量又称互斥锁.互斥量是一个可以处于两态之一的变量:解锁和加锁. 简介 编辑 如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量(mutex).互斥量仅仅适用于管理共享资源或一 ...
- C#线程同步(3)- 互斥量 Mutex
文章原始出处 http://xxinside.blogbus.com/logs/47162540.html 预备知识:C#线程同步(1)- 临界区&Lock,C#线程同步(2)- 临界区&am ...
随机推荐
- MyBatis面试题集合,90%会遇到这些问题
1.#{}和${}的区别是什么? ${}是Properties文件中的变量占位符,它可以用于标签属性值和sql内部,属于静态文本替换,比如${driver}会被静态替换为com.mysql.jdbc. ...
- Flask笔记:文件上传
文件上传 enctype:在HTML中的form表单中form标签默认是`enctype="application/x-www-form-urlencoded"`,在文件上传时需要 ...
- Mysql、Oracle、SQLServer等数据库参考文档免费分享下载
场景 MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统 ...
- 深入浅出《设计模式》之外观模式(C++)
前言 模式介绍 外观模式相比较之下比较简单,模式设计中定义是为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口是的这一子系统更加容易使用. 如果不理解呢,简单些说就是外观模式提 ...
- 腾讯WeTest亮相—腾讯全球数字生态大会现场
2019年5月21-23日腾讯全球数字生态大会在云南昆明滇池国际会展中心顺利召开. 此次大会上万人到场参与,大会由主峰会.分论坛.数字生态专题展会以及腾讯数字生态人物颁奖盛典四大板块构成.作为腾讯战略 ...
- vue中利用Promise封装jsonp并调取数据
Promise就是一个给一步操作提供的容器,在这个容器里,有两个阶段无法改变的阶段,第一个阶段就是Pending(进行),第二个阶段就是结果阶段,包含Fulfilled(成功).Rejected(失败 ...
- 1.监控软件zabbix-入门
入门学习 首先要明白zabbix的读音(音同zæbix),主要进行网络相关的监控.它是一个基于WEB界面展示提供分布式系统监控的一款开源软件. zabbix有两部分:zabbix server和zab ...
- MySQL的select(极客时间学习笔记)
查询语句 首先, 准备数据, 地址是: https://github.com/cystanford/sql_heros_data, 除了id以外, 24个字段的含义如下: 查询 查询分为单列查询, 多 ...
- docker研究-4 docker镜像制作
这次实验以centos镜像为基础镜像进行相关docker镜像制作. 1. 下载centos镜像 [root@localhost ~]# docker pull centosUsing default ...
- 201871010110-李华《面向对象程序设计(java)》第十五周学习总结
博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...