04-C++多线程编程-多线程互斥锁的多种实现方法

lock_guard
内部构造时相当于lock,析构时相当于执行unlock。
简单但不如lock()和unlock()灵活,通过大括号来实现,控制生命周期。

unique_lock
std::unique_lock要比std::lock_guard功能更多,有更多的成员函数,更灵活。
但是更灵活的代价是占用空间相对更大一些且相对更慢一些。

std::adopt_lock
adopt 通过,采取
表示mutex在此之前已经被上锁,不需要再lock了。
注意,必须提前lock。

std::unique_lock::try_lock/std::try_to_lock
尝试去加锁,如果没有锁定成功,会立即返回,不会产生阻塞。
前提:不能提前lock();
应用:防止其他的线程锁定mutex太长时间,导致本线程一直阻塞。

std::defer_lock
defer 延迟
功能:初始化了一个没有加锁的mutex
应用:不给它加锁的目的是以后可以调用unique_lock的一些方法。
前提:不能提前lock。

std::unique_lock::owns_lock()
当mutex被unique_lock上锁,且mutex没有解锁或析构,返回真,否则返回false。
不可复制。但是它是可以转移的(std::move)

/**
* By kkmd66
 *
 * 代码演示
 * 1、lock()、unlock()成对使用,返回时忘记的情况
 * 2、lock_guard的使用
 * 3、std::adopt_lock
 * 4、std::defer_lock
 * 5、std::try_to_lock
 * 6、std::unique_lock::release
 * 7、转移互斥锁所有权
*/

#include "iostream"
//多线程的头文件
#include "thread"
#include "list"
//互斥锁的头文件
#include "mutex"

using namespace std;

#define USE_LOCK_UNLOCK
#define USE_LOCKGUARD
#define USE_UNIQUELOCK
#define USE_ADOPTLOCK           //已经提前lock
#define USE_DEFER_LOCK          //互斥量没有lock,不能提前lock,只能后面lock
#define USE_TRY_TO_LOCK         //尝试去lock(不能提前lock),lock失败会返回,防止阻塞
#define USE_RELEASE             //解除所有权
#define USE_MOVE                //移除所有权

class DealData {

public:
    void putInData() {
        //数字增大可以增加冲突概率
        for (int i = 0; i < 1000; ++i) {
#ifdef USE_LOCK_UNLOCK
            myMutex.lock();
            cout << "putInData 子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
            myMutex.unlock();
#endif  //USE_LOCK_UNLOCK

#ifdef USE_LOCKGUARD
            lock_guard<mutex> dataGuard(myMutex);
            cout << "putInData 子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
#endif  //  USE_LOCKGUARD

#ifdef USE_UNIQUELOCK
            unique_lock<mutex> dataOutUnique(myMutex);
            cout << "putInData 子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
#endif  //USE_UNIQUELOCK

#ifdef USE_ADOPTLOCK
            //使用std::adopt_lock 必须先lock
            myMutex.lock();
            unique_lock<mutex> dataControl(myMutex, std::adopt_lock);
            cout << "putInData子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
#endif //USE_ADOPTLOCK

#ifdef USE_DEFER_LOCK
            //std::defer_lock 使用myMutex没有加锁
            unique_lock<mutex> dataControl(myMutex, std::defer_lock);
            myMutex.lock();
            //处理共享代码
            cout << "putInData子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
            myMutex.unlock();
            //处理非共享代码
            //....
            //使用try_lock功能类似try_to_lock
            if (myMutex.try_lock() == true) {
                //如果拿到了锁
                cout << "putInData子线程:放入一个数据" << i << endl;
                dataQuene.push_back(i);
            } else {
                //如果没有拿到锁
                cout << "putInData 子线程:没拿到锁" << i << endl;
            }
#endif  //USE_DEFER_LOCK

#ifdef USE_TRY_TO_LOCK
            //使用std::try_to_lock之前不能lock,否则会lock两次出错
            unique_lock<mutex> dataControl(myMutex, std::try_to_lock);
            if (dataControl.owns_lock()) {
                //如果拿到了锁
                cout << "putInData子线程:放入一个数据" << i << endl;
                dataQuene.push_back(i);
            } else {
                //如果没有拿到锁
                cout << "putInData 子线程:没拿到锁" << i << endl;
            }
#endif  //USE_TRY_TO_LOCK

#ifdef USE_RELEASE
            //把dataControl和myMutex绑定在一起,dataControl有myMutex的所有权
            unique_lock<mutex> dataControl(mutex);

            //释放了dataControl对myMutex的所有权,由pControl接管
            std::mutex *pControl = dataControl.release();
            cout << "putInData子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);

            pControl->unlock();
            //非共享数据
            //....
#endif  //USE_RELEASE

#ifdef USE_MOVE
            unique_lock<mutex> dataControl1(myMutex);
            //unique_lock<mutex> dataControl2(dataControl1);    //不能复制所有权
            unique_lock<mutex> dataControl2(std::move(dataControl1));   //可以移动所有权

            cout << "putInData子线程:放入一个数据" << i << endl;
            dataQuene.push_back(i);
#endif  //USE_MOVE
        }
    }

    void takeOutData() {
        while (1) {
            bool res = haveDta();
        }
    }

    //为了演示lock()、unlock()配对的重要性
    bool haveDta() {
#ifdef USE_LOCK_UNLOCK
        myMutex.lock();
        if (!dataQuene.empty()) {
            cout << "takeOutData子线程:取出一个数据" << dataQuene.front() << endl;
            dataQuene.pop_front();
            myMutex.unlock();       //不能忘记
            return true;
        }
        myMutex.unlock();
        return false;
#endif  //USE_LOCK_UNLOCK

#ifdef USE_UNIQUELOCK
        unique_lock<mutex> dataOutUnique(myMutex);
        if (!dataQuene.empty()) {
            cout << "takeOutData 子线程:取出一个数据" << dataQuene.front() << endl;
            dataQuene.pop_front();
            return true;
        }
        return false;
#endif  //USE_UNIQUELOCK

#ifdef USE_TRY_TO_LOCK
        unique_lock<mutex> dataControl(myMutex);
        std::this_thread::sleep_for(std::chrono::milliseconds(1));

        if (!dataQuene.empty()) {
            cout << "takeOutData 子线程:取出一个数据" << dataQuene.front() << endl;
            dataQuene.pop_front();
            return true;
        }
        return false;
#endif  //USE_TRY_TO_LOCK

        //DEFAULT
        unique_lock<mutex> dataOutUnique(myMutex);
        if (!dataQuene.empty()){
            cout << "takeOutData 子线程:取出一个数据" << dataQuene.front() << endl;
            dataQuene.pop_front();
            return true;
        }
        return false;
    }

private:
    std::list<int> dataQuene;
    mutex myMutex;
};


int main() {
//    std::list<int> dataQuene;

    //1、创建并开启线程,线程入口是putInData, takeOutData 函数
    DealData myData;
    thread putThread(&DealData::putInData, ref(myData));
    thread takeThread(&DealData::takeOutData, ref(myData));

    takeThread.join();
    putThread.join();

    return 1;
}

最后

有问题欢迎与我联系~
vx:kkmd66-2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值