【C++11多线程】多线程之数据共享

简介: 【C++11多线程】多线程之数据共享

前言

本节课的主要内容是解决线程中数据共享的问题


提示:以下是本篇文章正文内容,下面案例可供参考

一、数据共享的定义以及示例问题

数据共享的定义:在多个线程中读/写一个变量。

那我们首先要知道:变量能同时读取一个数据但不能同时写和读或者一起写同一个数据。

数据我们可以定义为全局变量或类中的一个成员。

二、解决方案_互斥量、lock()、unlock()

引导

功能为:myin()加数据到list中,myou()输出myin加入的数据

myin()功能为写,myou为读

大家可以试一下自己实现:

1、mutex互斥量

互斥量是上什么:如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量(mutex)

简单来说就是用来锁住一段代码,其他线程再次锁时就需要等待线程解锁

他在C++中头文件为:#include <mutex>

他是一个类

他的定义为:mutex m;

2、mutex::lock()锁

作用:用来锁住一段代码,其他线程使用时就需要等待解锁。

可以有效的缓解同时读/又读又写的线程

mutex m;
m.lock();//如果没有及时解锁,则:锁到程序结束,并且其他人拿不到锁
........
cout<<"hello world"<<endl;

3、mutex::unlock()解锁

作用:用来解锁一段代码,其他线程可以在次锁这个互斥量。

锁的意义:不让变量同时读写

4、范例演示

讲解:我们有2个线程,他们又读又写,所以我们需要锁住变量以保证数据安全。

我们使用完数据后也需要解锁,要不然其他线程会卡到lock()永远执行不到

class A
{
public:
  //功能为:myin()加数据到li中,myou()输出myin加入的数据
  void myin()
  {
    for (int i = 0; i < 100000; i++)
    {
      cout << "插入数据:" << i << endl;
      m.lock();//加锁保护数据安全
      li.push_back(i);
      m.unlock();//使用完后需要及时解锁
    }
  }
  void myou()
  {
    for (int i = 0; i < 100000; i++)
    {
      m.lock();//加锁保护数据安全
      if (!li.empty())//不为空时输出数据并删除他
      {
        //输出数据
        cout << "数据输出:" << li.front() << endl;
        li.pop_front();
      }
      else//为空则取不到
        cout << "队列为空" << endl;
      m.unlock();//使用完后需要及时解锁
    }
  }
  //定义一个list队列
  list<int> li;
  //定义一个互斥量
  mutex m;
};
int main()
{
  A a;
  //创建2个线程
  thread t(&A::myin);
  thread th(&A::myou);
  //让主线程等待
  t.join();
  th.join();
  return 0;
}


现在就可以稳定地跑起来了。

三、lock_gurad类模板、死锁及解决方案

1、为什么要使用lock_gurad

我相信,有些人lock()后总会忘记unlock()导致其他线程执行不到,卡在lock()那

怎么办呢?系统/C++给我们提供了一个类模板,使用他就不用unlock()了

2、lock_gurad的使用

他其实就是一个类模板

他的作用是不用unlock锁了,他自动unlock()

改一下刚刚的范例:

void myin()
  {
    for (int i = 0; i < 100000; i++)
    {
      cout << "插入数据:" << i << endl;
      lock_guard<mutex> lo(m);
      li.push_back(i);
    }
  }
  void myou()
  {
    for (int i = 0; i < 100000; i++)
    {
      lock_guard<mutex> lo(m);
      if (!li.empty())//不为空时输出数据并删除他
      {
        //输出数据
        cout << "数据输出:" << li.front() << endl;
        li.pop_front();
      }
      else
        cout << "队列为空" << endl;
    }
  }

他还是能正常运行,所以我们写的没有问题

他还有一个功能:变成unlock()

在lock_gurad构造函数参数2写adopt_lock

拓展知识std::lock:一次锁住多个mutex互斥量:

实际:类模板

mutex _1;
mutex _2;
std::lock<mutex>(_1,_2);

3、死锁情况的演示

大概情况讲解:线程A拿到mu1锁,在拿mu2锁,然后解锁mu2,解锁mu1 线程B呢:拿mu2锁,再拿mu1,然后解锁mu1,解锁mu2。这就导致有可能A,B都不解锁。卡在那:

解决方案:锁和解锁两个线程顺序要一样

四、unique_lock lock_gurad加强版

1、与lock_gurad的对比

为什么说unique_lock是 lock_gurad的加强版呢?

答:unique_lock用法更灵活,更多的参数,更高的效率

2、使用

unique_lock也是一个类模板

基本功能和lock_gurad一样一样的,那他灵活在哪呢?

成员函数,和构造函数的参数1多种多样:

构造函数参数1:

1).try_to_lock

没有拿到锁立马返回,立马unlock

怎么看自己有没有拿到锁呢

使用owns_lock函数

unique_lock<mutex> uni(m);
if(uni.owns_lock)
{
  cout<<"拿到了锁"<<endl;
  //干其他的事情
}
else
  cout<<"没有拿到锁"

2).defer_lock

初始化一个mutex

前提:此mutex没有加锁


成员函数:

1).lock()

手动lock()


2).unlock()

手动unlock()

unique_lock可以自己加解锁


3).release()放弃mutex的所以权,并返回mutex的指针

所有权指的是:放弃他的操作,简单的说:调用了release函数就不能操作那个绑定的mutex


相关文章
|
15天前
|
消息中间件 监控 安全
服务Down机了,线程池中的数据如何保证不丢失?
在分布式系统与高并发应用开发中,服务的稳定性和数据的持久性是两个至关重要的考量点。当服务遭遇Down机时,如何确保线程池中处理的数据不丢失,是每一位开发者都需要深入思考的问题。以下,我将从几个关键方面分享如何在这种情况下保障数据的安全与完整性。
41 2
|
1月前
|
消息中间件 存储 Java
服务重启了,如何保证线程池中的数据不丢失?
【8月更文挑战第30天】为确保服务重启时线程池数据不丢失,可采用数据持久化(如数据库或文件存储)、使用可靠的任务队列(如消息队列或分布式任务队列系统)、状态监测与恢复机制,以及分布式锁等方式。这些方法能有效提高系统稳定性和可靠性,需根据具体需求选择合适方案并进行测试优化。
|
2月前
|
Java 调度
基于C++11的线程池
基于C++11的线程池
|
2月前
|
数据处理 Python
解锁Python多线程编程魔法,告别漫长等待!让数据下载如飞,感受科技带来的速度与激情!
【8月更文挑战第22天】Python以简洁的语法和强大的库支持在多个领域大放异彩。尽管存在全局解释器锁(GIL),Python仍提供多线程支持,尤其适用于I/O密集型任务。通过一个多线程下载数据的例子,展示了如何使用`threading`模块创建多线程程序,并与单线程版本进行了性能对比。实验表明,多线程能显著减少总等待时间,但在CPU密集型任务上GIL可能会限制其性能提升。此案例帮助理解Python多线程的优势及其适用场景。
28 0
|
2月前
|
缓存 Java 容器
多线程环境中的虚假共享是什么?
【8月更文挑战第21天】
25 0
|
2月前
|
Dart 编译器 API
Dart ffi 使用问题之在C++线程中无法直接调用Dart函数的问题如何解决
Dart ffi 使用问题之在C++线程中无法直接调用Dart函数的问题如何解决
|
2月前
|
Dart API C语言
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
Dart ffi 使用问题之想在C/C++中创建异步线程来调用Dart方法,如何操作
|
15天前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
60 30
|
4天前
|
并行计算 Unix Linux
超级好用的C++实用库之线程基类
超级好用的C++实用库之线程基类
12 4
|
4天前
|
C++ Windows
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
HTML+JavaScript构建C++类代码一键转换MASM32代码平台