一、互斥量

1.1 互斥量的基本概念

简单来说,一个锁就是一个互斥量,既然是锁,就有两种状态:加锁和解锁,通过加锁>>>操作共享数据>>>解锁的方式,实现保护共享数据。

1.2 互斥量的用法

作用:在给某段代码加锁后,如果其他其他线程需要先等带该段代码执行完,然后解锁后才能继续执行。

头文件 :#include <mutex>

成员函数:lock()   //加锁,unlock()  //解锁

注意点:lock()与unlock()的使用必须成对存在。

 #include <iostream>
#include <mutex>
using namespace std;
int num = ;
mutex my_mutex; //创建一个互斥量
void print1()
{
for (int i = ; i < ; i++)
{
my_mutex.lock();
cout << "thread_1:" << num++ << endl;
my_mutex.unlock();
}
}
void print2()
{
for (int i = ; i < ; i++)
{
my_mutex.lock();
cout << "thread_2:" << num++ << endl;
my_mutex.unlock();
}
} int main()
{
thread thread_1(print1); //打印0-49
thread thread_2(print2); //打印49-99
thread_1.join();
thread_2.join();
system("pause");
return ;
}

还有一种方法,可实现加锁和解锁两个步骤,即用std::lock_guard<mutex> myguard (my_mutex)来代替lock()和unlock(),其原理是,在std::lock_guard构造函数里执行了lock(),在析构函数里执行了unlock()。

 #include <iostream>
#include <mutex>
using namespace std;
int num = ;
mutex my_mutex;
void print1()
{
for (int i = ; i < ; i++)
{
lock_guard<mutex> myguard(my_mutex);
cout << "thread_1:" << num++ << endl;
}
}
void print2()
{
for (int i = ; i < ; i++)
{
lock_guard<mutex> myguard(my_mutex);
cout << "thread_2:" << num++ << endl;
}
} int main()
{
thread thread_1(print1); //打印0-49
thread thread_2(print2); //打印49-99
thread_1.join();
thread_2.join();
system("pause");
return ;
}

二、死锁

仅在存在两个互斥量以上才会出现死锁的现象。例如线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都永远处于挂起状态了。通俗来讲,就是我在等你解锁我才能解锁,你在等我解锁你才能解锁。

 #include <iostream>
#include <mutex>
using namespace std;
int num = ;
mutex my_mutex1;
mutex my_mutex2;
void print1()
{
for (int i = ; i < ; i++)
{
my_mutex1.lock();
/*这里同通常有一段代码,也是用来操作共享数据*/
my_mutex2.lock();
cout << "thread_1:" << num++ << endl;
my_mutex1.unlock();
my_mutex2.unlock();
}
}
void print2()
{
for (int i = ; i < ; i++)
{
my_mutex2.lock();
my_mutex1.lock();
cout << "thread_2:" << num++ << endl;
my_mutex1.unlock();
my_mutex2.unlock();
}
} int main()
{
thread thread_1(print1); //打印0-49
thread thread_2(print2); //打印49-99
thread_1.join();
thread_2.join();
system("pause");
return ;
}

运行结果发现也不会出现任何奔溃出错现象,但是就一直卡在那里,不会继续运行下去了。

解决死锁的方法其实也很简单,只要保证互斥量加锁的顺序一致就可以了。或者使用std::lock(mutex1,mutex2),意思是给这两个互斥量同时上锁。

C++多线程基础学习笔记(五)的更多相关文章

  1. C++基础 学习笔记五:重载之运算符重载

    C++基础 学习笔记五:重载之运算符重载 什么是运算符重载 用同一个运算符完成不同的功能即同一个运算符可以有不同的功能的方法叫做运算符重载.运算符重载是静态多态性的体现. 运算符重载的规则 重载公式 ...

  2. java基础学习笔记五(抽象类)

    java基础学习总结——抽象类 抽象类介绍

  3. Java基础学习笔记(五) - 常用的API

    API介绍 概念:API 即应用编程程序接口.Java API是JDK中提供给我们使用的类说明文档,这些类将底层的代码实现封装.无需关心这些类是如何实现,只需要学习如何使用. 使用:通过API找到需要 ...

  4. Java基础学习笔记五 Java基础语法之面向对象

    面向对象 理解什么是面向过程.面向对象 面向过程与面向对象都是我们编程中,编写程序的一种思维方式.面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程.例如:公司打扫卫生( ...

  5. C++多线程基础学习笔记(四)

    一.创建多个子线程 前面三章讲的例子都是只有一个子线程和主线程,然而实际中有多个子线程.那么下面介绍如何创建多个子线程. #include <iostream> #include < ...

  6. C++多线程基础学习笔记(一)

    下面分三个方面多线程技术的必须掌握一些基本知识. 1.进程 2.线程 3.并发 (1)进程 一个可执行程序运行起来了,即为创建了一个进程.如在电脑上打开了word,就创建了一个word进程,打开QQ, ...

  7. loadrunner基础学习笔记五-场景

    场景目标:模拟10家旅行社同时登录.搜索航班.购买机票.查看航班路线并退出 负载测试是指在典型工作条件下测试应用程序,例如:多家旅行社同时在同一个机票预订系统中预订机票 controller提供所有用 ...

  8. JSP的范围-作用域(web基础学习笔记五)

    JSP的范围(作用域) 在JSP页面中的对象,包括用户创建的对象如JavaBean,都有一个范围属性,这个范围也被叫做“作用域”.范围定义了在什么时间内,在哪一个JSP页面中可以访问这些对象.例如,s ...

  9. C++多线程基础学习笔记(十)

    一.Windows临界区的基本用法 CRITICAL_SECTION my_winsc;              //定义一个Windows的临界区,相当于一个mutex变量 InitializeC ...

随机推荐

  1. CF1216E Numerical Sequence

    题目链接 问题分析 奇奇怪怪的题... 首先思路达成一致,从大到小一步一步确定位置. 我们一边分析,一边讲算法. 1121231234123451234561234567123456781234567 ...

  2. func<T> 和 action<T>

    一.Func Func<Result>,Func<T1,Result>是一个.Net内置的泛型委托. Func<TResult> Func<T,TResult ...

  3. 应用程序无法正常启动(0xc000007b)请单击确定关闭程序

    1.问题 在win10 VS2105 环境下面开发了一个调用get接口获取数据然后写入pg数据库的程序,在自己电脑上运行正常.复制到win7环境下运行,单击出现如下图所示的提示框. 2.原因分析 出现 ...

  4. typedef void(*Fun) (void)是什么意思 函数指针(回调函数) 和函数对象总结

    https://blog.csdn.net/FreeApe/article/details/49124043 bool (*pf)(const string &,const string &a ...

  5. flask入门第一篇

    一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比 1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不 ...

  6. 使用root配置的hadoop启动时报错

    一.报错信息: Starting namenodes on [master]         ERROR: Attempting to operate on hdfs namenode as root ...

  7. 修改PostgreSQL数据库的默认用户postgres的密码 并新建用户

    1.忘记了postgresql 安装时默认用户postgres 的密码,怎么办呢? linux shell命令下面输入: sudo -u postgres psql  (这样就可以直接登录进postg ...

  8. 【汇总】数据库提权(mysql、mssql)

    日期:2018-04-03 11:46:45 作者:Bay0net 介绍:利用 mssql 的 sa 账号提权.利用 MySQL 的 UDF 提权 0x01.mssql 提权 恢复 xp_cmdshe ...

  9. 给DBGrid动态赋值后,如何用程序指定某行某列为当前焦点?(100分)

    哈哈,我弄出来了.在大富翁上搜索的.Form1.DBGrid1.SelectedIndex := 4;Form1.DBGrid1.SetFocus;这样就行了.谢谢你! --------------- ...

  10. 007. Reverse Integer

    题目链接:https://leetcode.com/problems/reverse-integer/description/ Given a 32-bit signed integer, rever ...