C11 多线程初学1
C++ 11 多线程编程
- 1、线程的创建和使用
- 1.1 创建线程
- 1.2 线程的使用
- 2.实现线程同步
- 2.1互斥锁
- 2.2 条件变量
- 3.例
- 1:两线程交替打印奇偶数
1、线程的创建和使用
引入线程库<thread>,其提供了thread类,创建一个线程即实例化一个该类的对象,以此进行线程的创建和使用。
#include<thread>
using namespce std;
1.1 创建线程
一个线程可以用一个 thread 类的对象来表示,thread类中重载了构造函数和移动拷贝构造
#include<iostream>
#include<thread>using namespace std;void funa()
{cout << "thread_funa()" << endl;
}
int main()
{//创建线程——构造函数thread a(funa);cout << a.get_id() << endl;//移动拷贝构造thread b(std::move(a));cout << b.get_id() << endl;b.join();//移动拷贝构造进行资源的交换,所有要注释掉//a.join();cout << "main end" << endl;}
注意: thread类无拷贝构造函数、无赋值运算符,即不能直接用一个事先定义好的thread对象拷贝构造另一个thread对象,也不能不能进行赋值操作。但可以将临时的thread对象赋值给另一个thread即移动拷贝构造,也可以移动赋值。
1.2 线程的使用
thread 提供的函数: 线程支持库
thread类常用的成员函数:
成员函数 | 含义 |
---|---|
get_id() | 获取当前thread对象的线程id |
joinable() | 判断当前线程是否活跃(是:true;否:false)即是否支持调用 join() |
join() | 阻塞当前thread 对象所在的线程,直至thread 对象表示的线程执行完毕 |
detach() | 将当前线程从调用该函数的线程中分离出去,他们彼此独立运行 |
swap() | 交换两个线程的状态 |
注意:每个thread 对象在调用析构销毁前,要么调用 join() 函数令主线程等待子线程执行完毕,要么调用detach() 函数将子线程和主线程分离,二者必选一,否则存在以下问题:
- 线程占用的资源无法全部释放,造成内存泄露
- 当主线程执行完毕而子线程未完时,程序执行引发异常。
在this_thread 命名空间的部分函数:
函数 | 含义 |
---|---|
get_id() | 获得当前线程的 ID |
yield() | 阻塞当前线程让出cpu,直至条件成熟 |
sleep_for() | 阻塞当前线程指定的时间 |
sleep_until() | 阻塞当前线程,直至某个时间点为止 |
例:
//休眠1000毫秒,1s
this_thread::sleep_for(chrono::milliseconds(1000));
2.实现线程同步
2.1互斥锁
互斥锁用 mutex 类(位于std命名空间中)的对象表示,定义在头文件<mutex>头文件中。
成员函数:lock()——加锁; unlock()——解锁
例:对临界资源变量n的访问
#include<mutex>
using namespcase std;
mutex m; //实例化mutex对象m
void Show_n()
{m.lock();cout << n << endl;m.unlock();
}
实现严格基于作用域的互斥体所有权包装器:lock_fuard
原理:创建 lock_guard 对象时,它试图接收给定互斥的所有权。控制离开创建 lock_guard 对象的作用域时,销毁 lock_guard 并释放互斥。即,创建即加锁,作用域结束自动解锁。
#include<mutex>
using namespcase std;
mutex m; //实例化mutex对象m
void Show_n()
{lock_guard<mutex> g1(m);cout << n << endl;
}
//作用域结束,析构g1,m解锁
lock_gurad传入两个参数,第二个为adopt_lock标识时,表示该互斥量之前必须已经lock,才能使用此参数,故需要提前手动锁定。
#include<mutex>
using namespcase std;
mutex m; //实例化mutex对象m
void Show_n()
{m.lock(); //手动锁定lock_guard<mutex> g1(m, adopt_lock);cout << n << endl;
}
//作用域结束,析构g1,m解锁
实现可移动的互斥体所有权包装器:unique_lock
与lock_guard类似,用法更丰富。
成员函数 | 含义 |
---|---|
lock() | 锁定 |
try_lock() | 尝试锁定,若不能,先去执行其他代码并返回false;可以,进行加锁并返回true |
unlock() | 解锁 |
unique_lock与lock_guard
unique_lock | lock_guard | |
---|---|---|
手动lock、unlock | 支持 | 不支持 |
参数 | 支持 adopt_lock/try_to_lock/defer_lock | 支持 adopt_lock |
try_to_lock: 尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
defer_lock: 这个参数表示暂时先不lock,之后手动去lock,但是使用之前也是不允许去lock。
2.2 条件变量
C11提供的两种表示条件变量的类:
都定义在<condition_variable>头文件中,常与互斥锁搭配使用,避免线程间抢夺资源。
- condition_variable
该类表示的条件变量只能和unique_lock类表示的互斥锁搭配使用; - condition_variable_any
该类表示的条件变量可以与任意类型的互斥锁搭配使用(如:递归互斥锁、定时互斥锁等)
条件变量常用的成员函数
成员函数 | 功能 |
---|---|
wait() | 阻塞当前线程,等待条件成立 |
wait_for() | 阻塞当前线程的过程中,该函数会自动调用unlock()解锁,令其他线程使用公共资源。当条件成立或超过指定的等待时间,该函数自动调用lock()加锁,同时令线程继续执行 |
wait_until() | 与wait_for() 类似,区别是其可以设定一个具体的时间点,当条件成立或等待时间超过了指定的时间点,函数自动加锁,线程执行 |
notify_one() | 唤醒一个等待的线程 |
notify_all() | 唤醒所有等待线程 |
关于wait() :
调用wait()1先获得mutex,2线程被阻塞,当wait陷入休眠是会自动释放mutex。直到另外某个线程调用 notify_one或notify_all唤醒了当前线程。当线程被唤醒时,此时线程是已经自动占有了mutex。
3.例
1:两线程交替打印奇偶数
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
std::mutex data_mutex;
std::condition_variable data_var;
bool tag = true;
// odd : 1
// even: 2
// odd : 3
// even : 4void printodd() // 打印奇数
{std::unique_lock<std::mutex> ulock(data_mutex);for (int odd = 1; odd <= 100; odd += 2){while (!tag){data_var.wait(ulock);}cout << "odd: " << odd << endl;tag = false;data_var.notify_all();}
}
void printeven() //打印偶数
{std::unique_lock<std::mutex> ulock(data_mutex);for (int even = 2; even <= 100; even += 2){ while (tag){data_var.wait(ulock);// 1 2 }cout << "even: " << even << endl;tag = true;data_var.notify_all();}
}int main()
{thread thodd(printodd);thread theven(printeven);thodd.join();theven.join();return 0;
}
参考文献:
C++多线程unique_lock详解
C11 多线程初学1相关推荐
- c语言多线程的使用场合,C语言多线程,C11多线程完全攻略
C 程序中一直同时执行多项任务.例如c 多线程控制控件实例,一个程序也许: (1) 在执行程序过程中借助完成并行任务来提升性能. (2) 在处理用户输入的同时,在后台进行耗时的数据通信和即时操作. 通 ...
- 【最新版】Java速成路线(急于找工作!)
文章目录 计算机网络 分层结构 TCP/UDP HTTP/HTTPS 状态码 Cookie 和 Session URI和URL 操作系统 线程和进程 数据结构和算法 数据结构 算法 设计模式(23种) ...
- clang mingw
下载在线安装软件https://sourceforge.net/projects/mingw-w64/files/mingw-w64/ 1.Version制定版本号,从4.9.1-8.1.0,按需选择 ...
- Java小白到大神的心路历程(Java SE)
万事万物皆有其发展规律,学习Java也不例外. 以下是我根据教学经验,总结出来的小白在学习Java各阶段时的心路历程,当你在学习期间欣喜.困惑时,不妨看一看,也许这些都是必经之路. 使用Java完成第 ...
- 多线程java_初学Java要注意什么 怎么掌握Java多线程知识
初学Java要注意什么?怎么掌握Java多线程知识?很多初学Java的同学通常会对进程和线程傻傻分不清,进程和线程都是由操作系统所体会的程序运行的基本单元,一个程序至少有一个进程,一个进程至少有一个线 ...
- 初学Java多线程:线程简介
Java多线程初学者指南系列教程http://developer.51cto.com/art/200911/162925.htm 初学Java多线程:线程简介 2009-06-29 17:49 ...
- 初学Java多线程【1】:线程简介
一.线程概述 线程是程序运行的基本执行单元.当操作系统(不包括单线程的操作系统,如微软早期的DOS)在执行一个程序时,会在系统中建立一个进程,而在这个进程中,必须至少建立一个线程(这个线程被称为主线程 ...
- 【java初学】匿名内部类和多线程
文章目录 匿名内部类和多线程 1. 匿名内部类 1.1 接口你还记得吗??? 1.2 类的本体 2. 多线程 2.1 什么是进程 2.2 什么是线程 2.3 线程和进程的关系 2.4 线程优缺点 2. ...
- java 创建线程thread_初学Java多线程:用Thread类创建线程
在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程, ...
- 初学多线程使用中踩过的坑
wait使用,外面没有加synchronized ,导致频繁报错. IllegalMonitorStateException - 如果当前线程不是对象监视器的所有者报异常. wait使用时会释放锁.并 ...
最新文章
- 【Microsoft Word】编辑文字后,图片位置混乱的解决方法
- hdu 2544 最短路 Dijkstra算法
- VTK:图像透明度用法实战
- 获取Java接口的所有实现类
- jQuery Validate 合法性,限制性校验
- 只安装oracle服务端连plsql,Oracle 不安装Oracle客户端,使用PLSQL连接Oracle服务器
- 电子工程 计算机科学,计算机科学、计算机工程和电子工程有啥区别
- 【细节实现题】LeetCode 57. Insert Interval
- 配置元件--HTTP授权管理器
- php ajax可编辑表格,jquerAjax+php实现表格的增删改查(带数据库)
- jep java_jep-java-3.4-trial java表达式分析器 - 下载 - 搜珍网
- vi编辑器常用命令大全
- vlan tenant network on ovn based dvr (by quqi99)
- Javascript图片裁切
- 2020 web前端面试题及答案大全
- [转]使用jenkins实现持续集成
- 2020鼠年正月十一3000+股跌停后再次补仓
- 盛世昊通联手民族品牌CaldiceKris,创造价值互联
- Win7设置定时自动执行程序或脚本
- 计算机学院毕业礼物,“风里雨里,我们在这里等你“计算机学院举行毕业礼物赠予仪式...