C++11多线程之std::lock_guard和std::unique_lock

C++11多线程之std::lock_guard和std::unique_lock

在C++多线程对共享数据进行修改时,我们需要加互斥锁来保护数据被正确的读和写。C++提供了std::mutex,std::mutex在同一时间,只被一个线程拿到,而其他试图lock mutex的线程会被挂起(线程挂起的状态下CPU不会分给线程时间片,那么当前挂起的线程就会暂停运行。),直到该mutex被释放后,才有可能拿到mutex并继续执行。

  • 没有mutex的例子
#include <thread>
#include <iostream>
static int global = 0;
void threadTask()
{
   
   
    for (int i = 0; i < 100000000; i++) {
   
   
        global++;
    }
    std::cout << global << std::endl;
}
int main()
{
   
   
    std::thread t1(threadTask);
    std::thread t2(threadTask);
    std::thread t3(threadTask);
    
    t1.join();
    t2.join();
    t3.join();
    return 0;
}

运行结果
在这里插入图片描述
这个程序有3个线程,每个线程各做1亿次自加,但是运行结果并不是3亿。

mutex的使用

  • 使用mutex的例子
#include <thread>
#include <iostream>
static int global = 0;
std::mutex my_mutex;
void threadTask()
{
   
   
    for (int i = 0; i < 100000000; i++) {
   
   
   		my_mutex.lock();
        global++;
        my_mutex.unlock();
    }
    std::cout << global << std::endl;
}
int main()
{
   
   
    std::thread t1(threadTask);
    std::thread t2(threadTask);
    std::thread t3(threadTask);
    
    t1.join();
    t2.join();
    t3.join();
    return 0;

运行结果
my_mutex.unlock();

std::mutex的成员函数
  • lock():调用线程将锁住该互斥量。线程调用该函数会发生一下3种情况(1)如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一直拥有该锁。(2)如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。(3)如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)
  • unlock(),解锁释放对互斥量的所有权。
  • try_lock(),尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。线程调用该函数会出现以下3种情况(1)如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用unlock释放互斥量。(2)如果当前互斥量被其他线程锁住,则当前调用线程返回false,而并不会被阻塞掉。(3)如果当前互斥量被当前调用线程锁住,则会产生死锁。
std::time_mutex
  • try_lock_for 函数接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回false。
  • try_lock_until 函数则接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住,如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指定时间内还是没有获得锁),则返回false。

lock_guard的介绍和使用

  • 使用lock_guard可以对方便的管理对互斥量的加锁和解锁
    std::lock_gurad是C++11中定义的模板类。定义如下:
    template<class Mutex> class lock_guard;
    lock_guard对象用于管理某个锁对象,因此与Mutex RAII相关,方便线程对互斥量上锁,在某个lock_guard对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。
    (类似智能指针管理动态分配的内存资源)。lock_guard对象并不负责管理mutex对象的声明周期,lock_guard对象只是简化了mutex对象的上锁和解锁操作,方便线程对互斥量上锁,即在某个lock_guard对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而 lock_guard的生命周期结束之后,它所管理的锁对象会被解锁。
    lock_guard对象的拷贝构造和移动构造均被禁用,因此lock_guard对象不可被拷贝构造和移动构造。
  • 使用lock_guard的例子
#include <thread>
#include <iostream>
static int global = 0;
std::mutex my_mutex;
void threadTask()
{
   
   
    for (int i = 0; i < 100000000; i++) {
   
   
   		std::lock_guard<std::mutex> lock(my_mutex);
        global++;
    }
    std::cout << global << std::endl;
}
int main()
{
   
   
    std::thread t1(threadTask);
    std::thread t2(threadTask);
    std::thread t3(threadTask);
    
    t1.join()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值