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 
#include 
#include 

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 
#include 
#include 

std::mutex g_lck;

void fun()
{
    std::lock_guard 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 lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

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

    void Calc(int x, int y)
    {
        std::lock_guard 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 lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

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

    void Calc(int x, int y)
    {
        std::lock_guard 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 lck(mt);
        i *= x;
        std::cout << "i = " << i << std::endl;
    }

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

    void Calc(int x, int y)
    {
        //std::lock_guard 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") < 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 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 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
        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
        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 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
        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
        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 lock(mtx, std::defer_lock);
    lock.lock();
    std::cout << "thread #" << id << '\n';
    lock.unlock();
}

int main()
{
    std::vector 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 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 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 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 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 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 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 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 lock(mtx);
    ++count;
    print_count_and_unlock(lock.release());
}

int main()
{
    count = 0;

    std::vector 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 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 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 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 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 ReadLock;
typedef std::lock_guard 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 erupLock(m_mtErup);
        ReadLock lck(m_mtConn);
        for (auto it = m_jobIdAndConn.begin(); it != m_jobIdAndConn.end(); it++) {
            try {
                std::shared_ptr procClient = it->second->GetSrvClient();
                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 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)

你可能感兴趣的:(C++11-互斥量&锁)