C++11-互斥量&锁

互斥量

  • 用于线程同步,保证多线程访问共享数据的正确性

基本类型

std::mutex:独占的互斥量,不能递归使用

  • std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。
  • lock(),调用线程将锁住该互斥量。线程调用该函数会发生下面 3 种情况:(1). 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。(2).** 如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。**(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。
  • unlock(), 解锁,释放对互斥量的所有权。
  • try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数也会出现下面 3 种情况,(1). 如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用 unlock 释放互斥量。(2). 如果当前互斥量被其他线程锁住,则当前调用线程返回 false,而并不会被阻塞掉。(3). 如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。

std::timed_mutex:有超时功能的独占互斥量,不能递归使用

  • **try_lock_for **函数接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。参数为超时时间durantion。
  • **try_lock_until **函数则接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回 false。参数为时间点time_point

std::recursive_mutex:递归互斥量,能递归使用

  • std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock() 次数和 unlock() 次数相同,除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同。

std::recursive_timed_mutex:有超时功能的递归互斥量

  • 尽量不要使用递归互斥量
    • 容易产生程序逻辑问题
    • 效率比非递归锁低
    • 重复获得互斥量的最大次数不明确

std::shared_mutex(C++14)

  • std::shared_mutex用于管理可转移和共享所有权的互斥对象,适用场景比较特殊:一个或多个读线程同时读取共享资源,且只有一个写线程来修改这个资源,这种情况下才能从shared_mutex获取性能优势(Shared mutexes are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.
  • VC第一个支持shared_mutex的版本是VS2015 update2
  • http://en.cppreference.com/w/cpp/thread/shared_mutex

基本操作

lock&unlock

// C++_Mutex_Sample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <mutex>
#include <thread>
#include <iostream>

std::mutex g_lck;

void fun()
{
    g_lck.lock();
    std::cout << "thread " << std::this_thread::get_id() << " Do something_Begin " << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "thread " << std::this_thread::get_id() << " Do something_End" << std::endl;
    g_lck.unlock();
}

int main()
{
    std::thread thA(fun);
    std::thread thB(fun);
    std::thread thC(fun);

    thA.join();
    thB.join();
    thC.join();
    return 0;
 }

std::lock_gurad包装std::mutex

// C++_Mutex_Sample.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <mutex>
#include <thread>
#include <iostream>

std::mutex g_lck;

void fun()
{
    std::lock_guard<std::mutex> lck(g_lck);
    std::cout << "thread " << std::this_thread::get_id() << " Do something_Begin " << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "thread " << std::this_thread::get_id() << " Do something_End" << std::endl;
}


int main()
{
    std::thread thA(fun);
    std::thread thB(fun);
    std::thread thC(fun);

    thA.join();
    thB.join();
    thC.join();
    return 0;
}

std::recursive_mutex(解决递归死锁问题)

//死锁出错
struct Complex
{
    std::mutex mt;
    int i;

    Complex():i(1) {}

    void mul(int x)
    {
        std::lock_guard<std::mutex> lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

    void div(int x)
    {
        std::lock_guard<std::mutex> lck(mt);
        i /= x;
        std::cout << "i = " << i << std::endl;
    }

    void Calc(int x, int y)
    {
        std::lock_guard<std::mutex> lck(mt);
        mul(x);
        div(y);
    }
};

int main()
{
    Complex complex;
    complex.Calc(12, 4);
    return 0;
}
//解决方案1
struct Complex
{
    std::recursive_mutex mt;
    int i;

    Complex():i(1) {}

    void mul(int x)
    {
        std::lock_guard<std::recursive_mutex> lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

    void div(int x)
    {
        std::lock_guard<std::recursive_mutex> lck(mt);
        i /= x;
        std::cout << "i = " << i << std::endl;
    }

    void Calc(int x, int y)
    {
        std::lock_guard<std::recursive_mutex> lck(mt);
        mul(x);
        div(y);
    }
};

int main()
{
    Complex complex;
    complex.Calc(12, 4);
    return 0;
}

//解决方案2
struct Complex
{
    std::mutex mt;
    int i;

    Complex():i(1) {}

    void mul(int x)
    {
        std::lock_guard<std::mutex> lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

    void div(int x)
    {
        std::lock_guard<std::mutex> lck(mt);
        i /= x;
        std::cout << "i = " << i << std::endl;
    }

    void Calc(int x, int y)
    {
        //std::lock_guard<std::mutex> lck(mt);
        mul(x);
        div(y);
    }
};

int main()
{
    Complex complex;
    complex.Calc(12, 4);
    return 0;
}

std::timed_mutex(基本示例)

std::timed_mutex g_timeLock;

void Work()
{
    while (true)
    {
        if (g_timeLock.try_lock_for(std::chrono::milliseconds(1000)))
        {
            std::cout << "thread " << std::this_thread::get_id() << " Do something with time mutex" << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(2000));

            g_timeLock.unlock();
        }
        else
        {
            std::cout << "thread " << std::this_thread::get_id() << " Do something without mutex" << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        }
        //std::this_thread::sleep_for(std::chrono::milliseconds(2000));
    }

}

int main()
{
    std::thread t1(Work);
    std::thread t2(Work);

    t1.join();
    t2.join();

    return 0;
}

std::timed_mutex(try_lock_for/try_lock_until)

//一直让Work函数得不到g_timeLock,观察超时时间

std::t
imed_mutex g_timeLock;
void Work()
{
    while (true)
    {
        if (g_timeLock.try_lock_for(std::chrono::milliseconds(3000)))
        //std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
        //if (g_timeLock.try_lock_until(now + std::chrono::milliseconds(3000)))
        {
            auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
            std::cout << "thread " << std::this_thread::get_id() << " Do something with time mutex" << std::put_time(std::localtime(&t), "%Y-%m-%d %H.%M.%S") <<std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(2000));

            g_timeLock.unlock();
        }
        else
        {
            auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
            std::cout << "thread " << std::this_thread::get_id() << " Do something without mutex" << std::put_time(std::localtime(&t), "%Y-%m-%d %H.%M.%S") << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        }
    }
}

int main()
{
    std::lock_guard<std::timed_mutex> lck(g_timeLock);
    std::thread t1(Work);
    t1.join();
    return 0;
}

锁(互斥量管理类)

std::lock_guard

  • std::lock_guard严格基于作用域(scope-based)的锁管理类模板,构造时是否加锁是可选的(不加锁时假定当前线程已经获得锁的所有权),析构时自动释放锁,所有权不可转移,对象生存期内不允许手动加锁和释放锁。在默认构造函数里锁定互斥量,即调用互斥量的lock函数;析构函数里解锁互斥量,即调用互斥量的unlock函数
  • std::lock_guard 对象并不负责管理 Mutex 对象的生命周期,lock_guard 对象只是简化了 Mutex 对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个 lock_guard 对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 lock_guard 的生命周期结束之后,它所管理的锁对象会被解锁
  • lock_gurad的构造函数
  locking (1)           explicit lock_guard (mutex_type& m);
  • lock_guard 对象管理 Mutex 对象 m,并在构造时对 m 进行上锁(调用 m.lock())。
  adopting (2)      lock_guard (mutex_type& m, adopt_lock_t tag);
  • lock_guard 对象管理 Mutex 对象 m,与 locking 初始化(1) 不同的是, Mutex 对象 m 已被当前线程锁住。
  copy [deleted](3) lock_guard (const lock_guard&) = delete;

lock_guard 对象的拷贝构造和移动构造(move construction),赋值运算符均被禁用,因此 lock_guard 对象不可被拷贝构造或移动构造。

template<class _Mutex>
    class lock_guard<_Mutex>
    {   // specialization for a single mutex
      public:
        typedef _Mutex mutex_type;
      
        explicit lock_guard(_Mutex& _Mtx)
            : _MyMutex(_Mtx)
            {   // construct and lock
            _MyMutex.lock();
            }
      
        lock_guard(_Mutex& _Mtx, adopt_lock_t)
            : _MyMutex(_Mtx)
            {   // construct but don't lock
            }
      
        ~lock_guard() _NOEXCEPT
            {   // unlock
            _MyMutex.unlock();
            }
      
        lock_guard(const lock_guard&) = delete;
        lock_guard& operator=(const lock_guard&) = delete;
      private:
        _Mutex& _MyMutex;
    };

std::unique_lock

  • 与std:::lock_gurad基本一致,但更加灵活的锁管理类模板,构造时是否加锁是可选的,在对象析构时如果持有锁会自动释放锁,所有权可以转移。对象生命期内允许手动加锁和释放锁。但提供了更好的上锁和解锁控制(lock, unlock, try_lock等接口),尤其是在程序抛出异常后先前已被上锁的 Mutex 对象可以正确进行解锁操作,极大地简化了程序员编写与 Mutex 相关的异常处理代码。
  • unique_lock 对象以独占所有权的方式( unique owership)管理 mutex 对象的上锁和解锁操作,所谓独占所有权,就是没有其他的 unique_lock 对象同时拥有某个 mutex 对象的所有权。
  • std::unique_lock同样不能拷贝构造,但可以移动构造,在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。如果被赋值的对象之前已经获得了它所管理的 Mutex 对象的锁,则在移动赋值(move assignment)之前会调用 unlock 函数释放它所占有的锁。
template<class _Mutex>
    class unique_lock
    {   // whizzy class with destructor that unlocks mutex
public:
    typedef unique_lock<_Mutex> _Myt;
    typedef _Mutex mutex_type;

    // CONSTRUCT, ASSIGN, AND DESTROY
    //默认构造函数不管理任何Mutex对象
    unique_lock() _NOEXCEPT
        : _Pmtx(0), _Owns(false)
        {   // default construct
        }

    //传入Mutex对象,并尝试调用Mutex对象的lock()进行上锁
    //如果有另外的unique_lock对象已经管理了该Mutex对象,则当前线程会被阻塞
    explicit unique_lock(_Mutex& _Mtx)
        : _Pmtx(&_Mtx), _Owns(false)
        {   // construct and lock
        _Pmtx->lock();
        _Owns = true;
        }
    //传入Mutex对象,该Mutex对象已经被当前进程锁住了
    unique_lock(_Mutex& _Mtx, adopt_lock_t)
        : _Pmtx(&_Mtx), _Owns(true)
        {   // construct and assume already locked
        }
    //传入Mutex对象,不会锁住该Mutex对象
    unique_lock(_Mutex& _Mtx, defer_lock_t) _NOEXCEPT
        : _Pmtx(&_Mtx), _Owns(false)
        {   // construct but don't lock
        }
    //传入Mutex对象,并尝试调用Mutex对象的try_lock()进行上锁
    //上锁不成功,当前线程也不会阻塞
    unique_lock(_Mutex& _Mtx, try_to_lock_t)
        : _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock())
        {   // construct and try to lock
        }

    //传入Mutex对象,并尝试调用Mutex对象的try_lock_for(rel_time)进行上锁
    //锁住一段时间
    template<class _Rep,
        class _Period>
        unique_lock(_Mutex& _Mtx,
            const chrono::duration<_Rep, _Period>& _Rel_time)
        : _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_for(_Rel_time))
        {   // construct and lock with timeout
        }

        }

    //传入Mutex对象,并尝试调用Mutex对象的try_lock_until(rel_time)进行上锁
    //在某个时间点前锁住
    template<class _Clock,
        class _Duration>
        unique_lock(_Mutex& _Mtx,
            const chrono::time_point<_Clock, _Duration>& _Abs_time)
        : _Pmtx(&_Mtx), _Owns(_Pmtx->try_lock_until(_Abs_time))
        {   // construct and lock with timeout
        }

    unique_lock(_Mutex& _Mtx, const xtime *_Abs_time)
        : _Pmtx(&_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 = 0;
        _Other._Owns = false;
        }

    unique_lock& operator=(unique_lock&& _Other)
        {   // destructive copy
        if (this != &_Other)
            {   // different, move contents
            if (_Owns)
                _Pmtx->unlock();
            _Pmtx = _Other._Pmtx;
            _Owns = _Other._Owns;
            _Other._Pmtx = 0;
            _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&) 
    ...
    };

std::unique_lock的主要成员函数

  • 上锁/解锁操作:lock,try_lock,try_lock_for,try_lock_until 和unlock
  • 移动赋值:move Assignment.
  • 交换:swap
  • 释放:release
  • 是否获得了锁:owns_lock,operator bool()
  • 得到管理的mutex对象指针:mutex
template<class _Mutex>
    class unique_lock
    {   // whizzy class with destructor that unlocks mutex
public:
    ...
    // LOCK AND UNLOCK
    void lock()
        {   // lock the mutex
        _Validate();
        _Pmtx->lock();
        _Owns = true;
        }

    bool try_lock()
        {   // try to lock the mutex
        _Validate();
        _Owns = _Pmtx->try_lock();
        return (_Owns);
        }

    template<class _Rep,
        class _Period>
        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>
        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);
        }

    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_NCEE(system_error,
                _STD make_error_code(errc::operation_not_permitted));

        _Pmtx->unlock();
        _Owns = false;
        }

    // MUTATE
    void swap(unique_lock& _Other) _NOEXCEPT
        {   // swap with _Other
        _STD swap(_Pmtx, _Other._Pmtx);
        _STD swap(_Owns, _Other._Owns);
        }

    _Mutex *release() _NOEXCEPT
        {   // disconnect
        _Mutex *_Res = _Pmtx;
        _Pmtx = 0;
        _Owns = false;
        return (_Res);
        }

    // OBSERVE
    bool owns_lock() const _NOEXCEPT
        {   // return true if this object owns the lock
        return (_Owns);
        }

    explicit operator bool() const _NOEXCEPT
        {   // return true if this object owns the lock
        return (_Owns);
        }

    _Mutex *mutex() const _NOEXCEPT
        {   // return pointer to managed mutex
        return (_Pmtx);
        }
        ...
      }

std::unique_lock的使用

  • lock: 上锁操作,调用它所管理的 Mutex 对象的 lock 函数。如果在调用 Mutex 对象的 lock 函数时该 Mutex 对象已被另一线程锁住,则当前线程会被阻塞,直到它获得了锁。 该函数返回时,当前的 unique_lock 对象便拥有了它所管理的 Mutex 对象的锁。如果上锁操作失败,则抛出 system_error 异常。
std::mutex mtx;

void print_thread_id(int id)
{
    std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
    lock.lock();
    std::cout << "thread #" << id << '\n';
    lock.unlock();
}

int main()
{
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; i++){
        threads.emplace_back(print_thread_id, i + 1);
    }
    for (auto &th : threads){
        th.join();
    }
}

//output
thread #1
thread #5
thread #3
thread #10
thread #2
thread #6
thread #7
thread #8
thread #9
thread #4
  • try_lock: 上锁操作,调用它所管理的 Mutex 对象的 try_lock 函数,如果上锁成功,则返回 true,否则返回 false。
std::mutex mtx;

void print_star(int id)
{
    std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
    if (lock.try_lock()) {
        std::cout << "*";
    }
    else {
        std::cout << "x";
    }
    std::this_thread::sleep_for(std::chrono::microseconds(1000));
}
int main()
{
    std::vector<std::thread> threads;

    for (int i = 0; i < 500; i++) {
        threads.emplace_back(print_star, i + 1);
    }

    for (auto &th : threads) {
        th.join();
    }
}

//output
*xxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxx*xxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxx
  • try_lock_for: 上锁操作,调用它所管理的 Mutex 对象的 try_lock_for 函数,如果上锁成功,则返回 true,否则返回 false。
std::timed_mutex mtt;

void fireworks()
{
    std::unique_lock<std::timed_mutex> lock(mtt, std::defer_lock);

    while (!lock.try_lock_for(std::chrono::microseconds(200))) {
        std::cout << "-";
    }

    std::this_thread::sleep_for(std::chrono::microseconds(1000));
    std::cout << "*\n";
}

int main()
{
    std::vector<std::thread> threads;

    for (int i = 0; i < 10; i++) {
        threads.emplace_back(fireworks);
    }

    for (auto &th : threads) {
        th.join();
    }
}
//output
*
---------*
--------*
-------------*
-----*
----*
---*
--*
-*
-*
  • try_lock_until: 上锁操作,调用它所管理的 Mutex 对象的 try_lock_for 函数,如果上锁成功,则返回 true,否则返回 false。
std::timed_mutex cinderella;

void carriage() 
{
    std::unique_lock<std::timed_mutex> lock(cinderella, std::defer_lock);

    if (lock.try_lock_until(std::chrono::system_clock::now() + std::chrono::seconds(2))) {
        std::cout << "ride back home on carriage\n";
        lock.unlock();
    }
    else {
        std::cout << "carriage reverts to pumpkin\n";
    }
}

void ball()
{
    std::unique_lock<std::timed_mutex> lock(cinderella, std::defer_lock);
    lock.lock();
    std::cout << "at the ball...\n";
    std::this_thread::sleep_for(std::chrono::seconds(3));
}

int main()
{
    std::thread th1(ball);
    std::thread th2(carriage);

    th1.join();
    th2.join();
}
//output
at the ball...
carriage reverts to pumpkin
  • release: 返回指向它所管理的 Mutex 对象的指针,并释放所有权。
std::mutex mtx;
std::atomic<int> count;

void print_count_and_unlock(std::mutex* p_mtx)
{
    std::this_thread::sleep_for(std::chrono::microseconds(1000));
    std::cout << "count: " << count << '\n';
    p_mtx->unlock();
}

void task()
{
    std::unique_lock<std::mutex> lock(mtx);
    ++count;
    print_count_and_unlock(lock.release());
}

int main()
{
    count = 0;

    std::vector<std::thread> threads;

    for (int i = 0; i < 10; i++) {
        threads.emplace_back(task);
    }

    for (auto &th : threads) {
        th.join();
    }
}
//output
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
count: 10
  • owns_lock & operator bool(): 返回当前 std::unique_lock 对象是否获得了锁。
std::mutex mtx;

void print_star()
{
    std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);

    //if (lock.owns_lock()) {
    if (lock) {
        std::cout << '*';
    }
    else {
        std::cout << 'x';
    }
    std::this_thread::sleep_for(std::chrono::microseconds(1000));
}

int main()
{
    std::vector<std::thread> threads;

    for (int i = 0; i < 500; i++) {
        threads.emplace_back(print_star);
    }

    for (auto &th : threads) {
        th.join();
    }
}
//output
*xxxxx*xxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxx*xxxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxx*xxxxxxxxxxxxx*xxxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxxxxxxxxxxxxx*xxxxx*xxxxxxxxxxx*xxxxxxxxxxxxxx
  • mutex: 返回当前 std::unique_lock 对象所管理的 Mutex 对象的指针。
class MyMutex : public std::mutex {
    int m_id;
public:
    MyMutex(int id) :m_id(id) 
    {

    }

    int id()
    {
        return m_id;
    }
};

MyMutex mtx(100);

void print_ids(int id)
{
    std::unique_lock<MyMutex> lock(mtx);
    std::cout << "thread #" << id << " locked mutex " << lock.mutex()->id() << '\n';
    std::this_thread::sleep_for(std::chrono::microseconds(1000));
}


int main()
{
    std::vector<std::thread> threads;

    for (int i = 0; i < 10; i++) {
        threads.emplace_back(print_ids, i+1);
    }

    for (auto &th : threads) {
        th.join();
    }
}
//output
thread #1 locked mutex 100
thread #2 locked mutex 100
thread #3 locked mutex 100
thread #4 locked mutex 100
thread #5 locked mutex 100
thread #6 locked mutex 100
thread #7 locked mutex 100
thread #8 locked mutex 100
thread #9 locked mutex 100
thread #10 locked mutex 100

std::shared_lock

  • shared_lock是read lock。搭配std::shared_mutex使用,被锁后仍允许其他线程执行同样被shared_lock的代码。
  • lock_guard和unique_lock是write lock。被锁后不允许其他线程执行被shared_lock或unique_lock的代码。
typedef std::shared_lock<std::shared_mutex> ReadLock;
typedef std::lock_guard<std::shared_mutex> WriteLock;
int ReconCoordinator::SearchPort(int jobId)
{
    int port = 0;
    ReadLock lck(m_mtConn);


    auto it = m_jobIdAndPort.find(jobId);
    if (it != m_jobIdAndPort.end()) {
        port = it->second;
    }
    return port;
}
void ReconCoordinator::FlushConn()
{
    int jobId = 0;
    bool flushFlag = false;
    {
        std::lock_guard<std::mutex> erupLock(m_mtErup);
        ReadLock lck(m_mtConn);
        for (auto it = m_jobIdAndConn.begin(); it != m_jobIdAndConn.end(); it++) {
            try {
                std::shared_ptr<ErupProcServiceClient> procClient = it->second->GetSrvClient<ErupProcServiceClient>();
                procClient->Alive();    
            }
            catch (TException&) {
                flushFlag = true;
                jobId = it->first;
                break;
            }
        }
    }


    if (flushFlag) {
        if (jobId > ERUP_STANDBY_ID_MAX) {
            rcLog.LOG_WARN("ReconCoordinator, Zombie erup conn flush, jobId: %d", jobId);
        }
        else {
            rcLog.LOG_WARN("ReconCoordinator, Buffered zombie erup conn flush");
        }


        DestroyProcess(jobId);
        NotifyError(jobId);
    }
}
void ReconCoordinator::ClearPortInfo(int jobId)
{
    WriteLock lck(m_mtInfo);
    m_requiredInfo->ClearProtInfo(jobId);
}
void ReconCoordinator::InitFailed(int jobId)
{
    //rcLog.LOG_WARN("Erup process initialize failed, jobId: %d", jobId);
    if (jobId <= ERUP_STANDBY_ID_MAX) 
    {
        {
            WriteLock lck(m_mtConn);
            m_jobIdAndPort.erase(jobId);
        }
        {
            WriteLock lck(m_mtState);
            m_jobIdAndState.erase(jobId);
        }
        {
            std::lock_guard<std::mutex> lck(m_mtProc);
            auto it = m_jobIdAndProcess.find(jobId);
            if (it == m_jobIdAndProcess.end()) {
                rcLog.LOG_INFO("Erup process not exists in NotifyInitFailed, jobId: %d", jobId);
            }
            else {
                ::TerminateProcess(it->second, 0);
                ::CloseHandle(it->second);
                m_jobIdAndProcess.erase(it);
            }
        }
    }
}

加锁策略参数

  • 互质量管理类在构造时是否加锁是可选的,C++11提供了以下3种加锁策略,及其支持情况
策略 tag type 描述
(默认) 请求锁,阻塞当前线程直到成功获得锁。
std::defer_lock std::defer_lock_t 不请求锁。
std::try_to_lock std::try_to_lock_t 尝试请求锁,但不阻塞线程,锁不可用时也会立即返回。
std::adopt_lock std::adopt_lock_t 假定当前线程已经获得互斥对象的所有权,所以不再请求锁。
策略 描述 std::lock_guard std::unique_lock std::shared_lock
(默认) 请求锁,阻塞当前线程直到成功获得锁。 √(共享)
std::defer_lock 不请求锁。 ×
std::try_to_lock 尝试请求锁,但不阻塞线程,锁不可用时也会立即返回。 ×
std::adopt_lock 假定当前线程已经获得互斥对象的所有权,所以不再请求锁。

官方解释:https://zh.cppreference.com/w/cpp/thread/lock_tag

原子锁操作

  • 有时需要同时对多个互斥量上锁,可使用:std::lock和std::try_lock
std::lock(mt1, mt2)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342