多线程 mutex的理解

mutex,我的理解是每个mutex对象都是一个带锁头的门,这个门有两个状态,门开着和门关着,感觉像是废话。。。

当想查看门的里东西,或者把东西放进门里,或者从门里拿出东西前,都需要看看,门是否是打开的。

  • 如果门是打开的,就要进去后赶紧把门关上。关上后,就可以查看屋子里的东西,放东西到屋子里,从屋子里拿东西。
  • 如果门是关着的,就要在外面等着,直到有人出来时,把门打开了,你才能进去。

每个mutex都是不同的门,当你用mutex a锁上了一个门,就只能用mutex a去打开,用mutex b是打不开,切记。

例子:用mutex a锁门,用metex b去开门,结果没打开,就导致了程序的死锁。

注意:这个程序专门为了测试,mutex的问题。

#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h> using namespace std; class data_protect{
public:
list<int> alist{1,2};
mutex m;
mutex m1;
public: void add_list(int val){
m.lock(); //----------------①
alist.push_back(val);
}
bool contains(int val){
m1.unlock();//----------------------②
return find(alist.begin(), alist.end(), val) != alist.end();
}
}; void func(data_protect& dp){
dp.add_list(12);
} int main(){
data_protect dp;
thread t(func, ref(dp));
//t.join();
t.detach();//---------------③
//sleep(1);
dp.add_list(12);//----------------④
if(dp.contains(12)){//------------------⑤
cout << "contains 12" << endl;
}
for(auto& s : dp.alist){
cout << s << endl;
}
pthread_exit(NULL); }

执行结果:死锁,程序永远在等待锁的打开。

执行结果分析:

从③处开始就开了一个新的线程a,线程a调用了add_list()方法,add_list方法里,在①处是用m去上的锁。main函数线程在④处也调用了,add_list()方法,进去后,发现是上锁的状态,所以就阻塞在哪里,等着锁打开后,main函数线程好进去,然后在⑤处调用了contains方法,contains方法试图在②处用m1去解m的锁,所以就解不开①处的锁,所以就导致了一个线程一直等在①处的锁的地方,就导致了死锁。

如果把②处的m1.unlock();换成m.unlock();就能解开锁了,就不会导致死锁。

想说明的东西,用哪个mutex上的锁,就得用哪个mutex去解锁。

mutex的正确使用方法:不是直接用调用mutex的lock,unlock方法。理由是在lock和unlock中间的某段代码如果崩溃掉,就会导致unlock方法没有被执行,也就导致了,锁没有解开,别线程再来访问时,就变成了死锁。

所以使用:std::lock_guard<std::mutex>,它的好处是,即使发生了异常也能自动解锁。

例子:

#include <list>
#include <iostream>
#include <mutex>
#include <algorithm>
#include <thread>
#include <unistd.h> using namespace std; class data_protect{
public:
list<int> alist{1,2};
mutex m;
public: void add_list(int val){
lock_guard<mutex> g(m);
alist.push_back(val);
}
bool contains(int val){
lock_guard<mutex> g(m);
return find(alist.begin(), alist.end(), val) != alist.end();
}
}; void func(data_protect& dp){
dp.add_list(12);
} int main(){
data_protect dp;
thread t(func, ref(dp));
//t.join();
t.detach();
//sleep(1);
dp.add_list(12);
if(dp.contains(12)){
cout << "contains 12" << endl;
}
for(auto& s : dp.alist){
cout << s << endl;
}
pthread_exit(NULL); }

c/c++ 学习互助QQ群:877684253

本人微信:xiaoshitou5854

c/c++ 多线程 mutex的理解的更多相关文章

  1. 多线程系列之 java多线程的个人理解(二)

    前言:上一篇多线程系列之 java多线程的个人理解(一) 讲到了线程.进程.多线程的基本概念,以及多线程在java中的基本实现方式,本篇主要接着上一篇继续讲述多线程在实际项目中的应用以及遇到的诸多问题 ...

  2. cpu个数、核数、线程数、Java多线程关系的理解

    cpu个数.核数.线程数.Java多线程关系的理解 2017年12月08日 15:35:37 一 cpu个数.核数.线程数的关系 cpu个数:是指物理上,也及硬件上的核心数: 核数:是逻辑上的,简单理 ...

  3. 我对java多进程多线程的浅显理解

    linux内核调度算法--CPU时间片如何分配: http://blog.csdn.net/russell_tao/article/details/7103012(转载)  ,通过该文章我们知道了进程 ...

  4. POSIX 多线程编程及理解

    最近开发基于ZYNQ的嵌入式linux程序,涉及到多线程使用,将一些内容整理如下: POSIX多线程编程最为基础和重要的可以分为两部分: 线程操作-Thread Management 线程同步-Syn ...

  5. iOS 多线程的简单理解(4) 线程锁的简单使用

    要用到多线程 ,就不得不考虑,线程之间的交互,线程是否安全 推荐一个原文链接 是关于 线程锁的基本使用的  http://blog.csdn.net/qq_30513483/article/detai ...

  6. 多线程锁--怎么理解Condition

    在java.util.concurrent包中,有两个很特殊的工具类,Condition和ReentrantLock,使用过的人都知道,ReentrantLock(重入锁)是jdk的concurren ...

  7. iOS开发中GCD在多线程方面的理解

    GCD为Grand Central Dispatch的缩写. Grand Central Dispatch (GCD)是Apple开发的一个多核编程的较新的解决方法.在Mac OS X 10.6雪豹中 ...

  8. 多线程系列之 Java多线程的个人理解(一)

    前言:多线程常常是程序员面试时会被问到的问题之一,也会被面试官用来衡量应聘者的编程思维和能力的重要参考指标:无论是在工作中还是在应对面试时,多线程都是一个绕不过去的话题.本文重点围绕多线程,借助Jav ...

  9. c# 多线程 --Mutex(互斥锁)

    互斥锁(Mutex) 互斥锁是一个互斥的同步对象,意味着同一时间有且仅有一个线程可以获取它. 互斥锁可适用于一个共享资源每次只能被一个线程访问的情况 函数: //创建一个处于未获取状态的互斥锁 Pub ...

随机推荐

  1. 侯哥的Python分享

    侯哥语录 我曾经是一个职业教育者,现在是一个自由开发者.我希望我的分享可以和更多人一起进步.分享一段我喜欢的话给大家:"我所理解的自由不是想干什么就干什么,而是想不干什么就不干什么.当你还没 ...

  2. java线程阻塞唤醒的四种方式

    java在多线程情况下,经常会使用到线程的阻塞与唤醒,这里就为大家简单介绍一下以下几种阻塞/唤醒方式与区别,不做详细的介绍与代码分析 suspend与resume Java废弃 suspend() 去 ...

  3. MySQL将utf8字符集改为utf8mb4

    前言 今天在查看tomcat日志时发现了一个错误:Cause: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x98\x82\xF0 ...

  4. Python内置函数(14)——delattr

    英文文档: delattr(object, name) This is a relative of setattr(). The arguments are an object and a strin ...

  5. qt之菜单项定制

    qt实现菜单,简单的界面QMenu+QAction完全可以实现,在加上qss的支持,可以定制出比较美观的菜单,qt的菜单一般用在托盘.按钮和工具栏上. 当然啦,也有很多软件有比较美观的托盘菜单,比如3 ...

  6. Redis学习——数据结构介绍(四)

    一.简介 作为一款key-value 的NoSQL数据库,Redis支持的数据结构比较丰富,有:String(字符串) .List(列表) .Set(集合) .Hash(哈希) .Zset(有序集合) ...

  7. eclipse连接Android8.0以上手机无法打印日志的问题

    概述 我的eclipse的环境: Eclipse:Eclipse IDE for Java DevelopersVersion: Luna Service Release 2 (4.4.2) Andr ...

  8. ASP.NET Core DI 手动获取注入对象

    ASP.NET Core DI 一般使用构造函数注入获取对象,比如在ConfigureServices配置注入后,通过下面方式获取: private IValueService _valueServi ...

  9. [七]基础数据类型之Float详解

        Float 基本数据类型float  的包装类 Float 类型的对象包含一个 float 类型的字段    属性简介 用来以二进制补码形式表示 float 值的比特位数 public sta ...

  10. 痞子衡嵌入式:常用的数据差错控制技术(1)- 重复校验(Repetition Code)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是嵌入式里数据差错控制技术-重复校验. 在嵌入式应用里,除了最核心的数据处理外,我们还会经常和数据传输打交道.数据传输需要硬件传输接口的支持 ...