C++关于锁的总结(一)

线程中的锁分为两种,互斥锁共享锁

相关的头文件有<mutex><shared_mutex>,前者具有std::unique_lock操作,用于实现互斥功能,后者具有std::shared_lock操作,用于完成共享锁操作。

这里先讨论std::shared_mutex这个类。

共享锁

如果需要使用共享锁,则需要使用到std::shared_mutex这个类。具体讲解见这里

该锁可用于保护被多个线程同时访问的共享数据。

std::shared_mutex有两种访问级别:

  • 共享:多个线程可以共享这个锁的拥有权。一般用于数据的读操作,防止数据被写修改。
  • 互斥:仅仅一个线程可以拥有这个锁。一般用于写操作。

如果一个线程已经获取了互斥锁,则其他线程都无法获取该锁。

如果一个线程已经获取了共享锁,则其他任何线程都无法获取互斥锁,但是可以获取共享锁

说到这里,为了实现该锁的互斥和共享,不得不介绍std::shared_lockstd::unique_lock这两个模板。前者定义在<shared_mutex>,后着定义在<mutex>中。

在下面的代码中均以测试过,编译选项为--std=c++1z -pthread;

由于c++中的cout不是线程安全的函数,所以给cout输出加上了互斥锁。

共享锁的代码示例

#include <shared_mutex>
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono> std::shared_mutex test_lock; std::mutex cout_lock; int arr[3] = {11, 22, 33}; void unique_lock_demo(int id)
{
std::unique_lock lock{test_lock}; for(int i =0; i < 3; i++)
{
arr[i] = i + 100 * id;
} for(int i = 0; i < 3; i++)
{
std::unique_lock pl(cout_lock);
std::cout << "In unique: " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
} void shared_lock_demo(int id)
{
std::shared_lock lock{test_lock}; for(int i = 0; i < 3; i++)
{
std::unique_lock pl(cout_lock);
std::cout << "In shared " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
} int main()
{ std::thread t3(unique_lock_demo,3);
std::thread t4(unique_lock_demo,4);
std::thread t1(shared_lock_demo,1);
std::thread t2(shared_lock_demo,2); t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}

输出为:

In unique: 3: 300
In unique: 3: 301
In unique: 3: 302
In shared 1: 300
In shared 2: 300
In shared 1: 301
In shared 2: 301
In shared 1: 302
In shared 2: 302
In unique: 4: 400
In unique: 4: 401
In unique: 4: 402

从这个输出可以看出:

  • 如果一个线程已经获取了共享锁,则其他任何线程都无法获取互斥锁,但是可以获取共享锁

  • 从这个输出可以看出,验证了如果一个线程已经获取了互斥锁,则其他线程都无法获取该锁。

注:关于上述代码有的平台运行不了,可以运行下面的代码


#include <shared_mutex>
#include <mutex>
#include <iostream>
#include <thread>
#include <chrono> std::shared_mutex test_lock; std::mutex cout_lock; int arr[3] = {11, 22, 33}; void unique_lock_demo(int id)
{
std::unique_lock<std::shared_mutex> lock(test_lock); for(int i =0; i < 3; i++)
{
arr[i] = i + 100 * id;
} for(int i = 0; i < 3; i++)
{
std::unique_lock<std::mutex> pl(cout_lock);
std::cout << "In unique: " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
} void shared_lock_demo(int id)
{
std::shared_lock<std::shared_mutex> lock(test_lock); for(int i = 0; i < 3; i++)
{
std::unique_lock<std::mutex> pl(cout_lock);
std::cout << "In shared " << id << ": " << arr[i] << std::endl;
pl.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
} int main()
{ std::thread t3(unique_lock_demo,3);
std::thread t1(shared_lock_demo,1);
std::thread t2(shared_lock_demo,2);
std::this_thread::sleep_for(std::chrono::seconds(4));
std::thread t4(unique_lock_demo,4); t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}

C++关于锁的总结(一)的更多相关文章

  1. 使用redis构建可靠分布式锁

    关于分布式锁的概念,具体实现方式,直接参阅下面两个帖子,这里就不多介绍了. 分布式锁的多种实现方式 分布式锁总结 对于分布式锁的几种实现方式的优劣,这里再列举下 1. 数据库实现方式 优点:易理解 缺 ...

  2. 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)

    前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...

  3. java中的锁

    java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...

  4. 分布式锁1 Java常用技术方案

    前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资 ...

  5. 如何在高并发环境下设计出无锁的数据库操作(Java版本)

    一个在线2k的游戏,每秒钟并发都吓死人.传统的hibernate直接插库基本上是不可行的.我就一步步推导出一个无锁的数据库操作. 1. 并发中如何无锁. 一个很简单的思路,把并发转化成为单线程.Jav ...

  6. 如何定位Oracle数据库被锁阻塞会话的根源

    首先再次明确下,数据库因为要同时保证数据的并发性和一致性,所以操作有锁等待是正常的. 只有那些长时间没有提交或回滚的事物,阻塞了其他业务正常操作,才是需要去定位处理的. 1.单实例环境 2.RAC环境 ...

  7. java 线程 Lock 锁使用Condition实现线程的等待(await)与通知(signal)

    一.Condition 类 在前面我们学习与synchronized锁配合的线程等待(Object.wait)与线程通知(Object.notify),那么对于JDK1.5 的 java.util.c ...

  8. Android 死锁和重入锁

    死锁的定义: 1.一般的死锁 一般的死锁是指多个线程的执行必须同时拥有多个资源,由于不同的线程需要的资源被不同的线程占用,最终导致僵持的状态,这就是一般死锁的定义. package com.cxt.t ...

  9. Xcode 锁终端

    锁终端 输入: <1>cd /Applications/Xcode.app 回车 结果显示: Xcode.app 输入: <2>sudo chown -hR root:whee ...

  10. mysql 行级锁的使用以及死锁的预防

    一.前言 mysql的InnoDB,支持事务和行级锁,可以使用行锁来处理用户提现等业务.使用mysql锁的时候有时候会出现死锁,要做好死锁的预防. 二.MySQL行级锁 行级锁又分共享锁和排他锁. 共 ...

随机推荐

  1. Java 程序是如何执行的

    Java 程序是如何执行的 了解任何一门语言的精髓都是先俯览其全貌,从宏观的视角把握全局,然后再深入每个知识点逐个击破,这样就可以深入而快速的掌握一项技能.同样学习 Java 也是如此,本节就让我们先 ...

  2. JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版)

    概述 JAVA对象引用体系除了强引用之外,出于对性能.可扩展性等方面考虑还特地实现了四种其他引用:SoftReference.WeakReference.PhantomReference.FinalR ...

  3. Codeforces_818

    A.winners总数为(k+1)diplomas. #include<bits/stdc++.h> using namespace std; long long n,k; int mai ...

  4. AI产品经理工作流程——需求分析和产品设计

    1.AI产品设计常见失败原因 技术驱动产品设计,即我有什么技术就做什么产品.尽管许多公司不惜重金招聘高级AI算法工程师,确实这样也能帮助企业拿到大量的融资,但也容易给公司带来技术决定产品设计的局限.然 ...

  5. 《深入理解Java虚拟机》第2版挖的坑终于在第3版中被R大填平了

    这是why技术的第34篇原创文章 本周还是在家办公的一周,上面的图就是我在家的工位,和上周<Dubbo Cluster集群那点你不知道的事>这篇文章里面的第一张图片比起来,升级了显示器支撑 ...

  6. Go语言实现:【剑指offer】连续子数组的最大和

    该题目来源于牛客网<剑指offer>专题. HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向 ...

  7. 2020牛客寒假算法基础集训营4 B:括号序列

    B : 括号序列 考察点 : 栈 坑点 : 只有栈空时才是合法的 Code: #include <stack> #include <cstdio> #include <s ...

  8. html标签学习入门 随笔

    Html学习入门    随笔1: HTML 标题 HTML 标题(Heading)是通过 <h1> - <h6> 等标签进行定义的. 标题仅用于标题文本  不应该被使用在加粗字 ...

  9. Generator - Python 生成器

    Generator, python 生成器, 先熟悉一下儿相关定义, generator function 生成器函数, 生成器函数是一个在定义体中存有 'yield' 关键字的函数. 当生成器函数被 ...

  10. Java Stack使用

    1.Stack继承自Vector.遵从先进后出的规则. 2.Stack 是线程同步的.(map.List.Set是线程不同步的,需要在外部封装的时候来同步) 试例代码: public static v ...