C++多线程之共享资源同步

在上一节里面,我们学习了如何通过c++来创建和管理线程,
这一节我们主要学习如何同步多线程中的资源。
什么是同步资源呢?简单来说就是实现多线程共享资源的安全访问,举个例子来说,如果两个线程都需要对同一个变量进行修改,如果不加控制的话,这个变量最后的结果可能就不是我们预期的结果了,大家先来看以下的代码示例:

  1. 无线程同步例子
#include<thread>
#include<iostream>
using namespace std;

int global_value = 0;

void myfunc1()
{
   for(int i=0;i<20;i++)
   {
      global_value++;
      cout<<"t1:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}
void myfunc2()
{
   for(int i=0;i<20;i++)
   {
      global_value++;
      cout<<"t2:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}

public static void main()
{
   thread t1(myfunc1);
   thread t2(myfunc2);
   t1.join();
   t2.join();
   cout<<"global_value at last:"<<global_value<<endl;
}
  1. 有线程同步的例子
#include<thread>
#include<mutex>
#include<iostream>
using namespace std;

std::mutex data_mutex
int global_value = 0;

void myfunc1()
{
   for(int i=0;i<20;i++)
   {
      data_mutex.lock();
      global_value++;
      data_mutex.unlock();
      cout<<"t1:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}
void myfunc2()
{
   for(int i=0;i<20;i++)
   {
      data_mutex.lock();
      global_value++;
      data_mutex.unlock();
      cout<<"t2:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}

public static void main()
{
   thread t1(myfunc1);
   thread t2(myfunc2);
   t1.join();
   t2.join();
   cout<<"global_value at last:"<<global_value<<endl;
}

大家可以把上面的例子先拷贝到自己的c++运行环境里面,运行结果对比一下。
大家会发现第一个例子中的值是多少呢?
第二个例子中的值又是多少呢?
为什么是这样的结果?

c++中线程同步的方法:

  • 互斥锁mutex

在上面的第二个例子中,我们使用了mutex来同步数据,mutex什么意思呢?mutex就是互斥锁,它的作用就是在访问一个变量之前先对其进行“上锁”,举个例子就好像我们大家都去试衣间试衣服的时候,我们会在门口挂一个牌子,告诉别人这个试衣间在使用中,那么别人要使用同一个试衣间都需要等到试衣间空闲的时候。互斥锁也是这个作用,当我们使用互斥锁对某一段代码加锁的后,如果另外的线程也要访问同一代码段的时候,它也使用同一个互斥锁去加锁,这个时候发现已经有其他线程加锁了,那么就一直等待,直到其他线程完成解锁操作以后,这个线程才可能加锁成功,进行相关代码段的访问。
参见下面代码片段:

#include<thread>
#include<mutex>
void myfunc2()
{
   for(int i=0;i<20;i++)
   {
      data_mutex.lock();
      global_value++;
      data_mutex.unlock();
      cout<<"t2:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}

c++ 里面申明mutex对象:
std::mutex data_mutex;
加锁操作:data_mutex.lock()
解锁操作:data_mutex.unlock()

这个操作需要lock和unlock配对操作,否则可能导致永远无法加锁成功。
可以简化加锁和解锁的配对操作,使用c++提供的另外一个包装类:std::lock_guard
使用std::lock_guard 改造上面的例子:

#include<thread>
#include<mutex>
void myfunc2()
{
   for(int i=0;i<20;i++)
   {
      std::lock_guard<std::mutex> guard(data_mutex);
      global_value++;
      cout<<"t2:"<<global_value<<endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(10));
   }
}

可以看出我们不用手动调用unlock函数,当每次for循环一次完成的时候,程序会自动解锁。
使用std::lock_guard对象可以有效避免忘了unlock导致的问题。
OK,下一节我们继续讲解其他的数据同步方式。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值