![](https://img-blog.csdnimg.cn/20201014180756928.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
C++并发编程实战
csdn_dzh
一些点滴的记录
展开
-
C++并发编程实战
该系列文章参考自《CPP Concurrency In Action》。一、C++并发编程入门1.1 并发的概念1.2 第一个并发程序1.3 花式创建线程1.4 线程结束和分离1.5 转移线程所有权1.6 线程数和线程ID...原创 2020-03-16 12:33:37 · 603 阅读 · 0 评论 -
基于UDP的简单聊天室
聊天室功能: 1.其他用户上线通知。 2.其他用户下线通知。 3.获取在线列表。 4.用户之间点对点聊天。实现思想: 1.服务器端主要是解析客户端发送过来的各种指令,并作出相应的处理和回应。 2.客户端采用select管理套接口IO和标准输入IO,当有事件发生,做出相应的处理。 3.采用链表存储每个客户端的网络信息,登录对应聊表...转载 2020-05-08 10:56:33 · 358 阅读 · 0 评论 -
select模型跨平台服务端/客户端
最近跟着刘远东老师的《C++百万并发网络通信引擎架...转载 2020-05-08 10:44:50 · 437 阅读 · 0 评论 -
epoll反应堆代码
#include <stdio.h>#include <sys/socket.h>#include <sys/epoll.h>#include <arpa/inet.h>#include <fcntl.h>#include <unistd.h>#include <errno.h>#include &l...原创 2020-04-01 23:08:58 · 229 阅读 · 0 评论 -
4.2 常见的 atomic
文章目录std::atomic_flagstd::atomic_flag 实现自旋互斥锁std::atomic< bool >std::atomic_flagstd::atomic_flag 是最简单的 bool 原子类型。std::atomic_flag 类型的对象必须被 ATOMIC_FLAG_INIT 初始化,初始化为 “清除” 状态,此时互斥量处于解锁状态。不能...原创 2020-03-23 17:25:03 · 269 阅读 · 0 评论 -
4.1 并发中的原子操作
文章目录对象、内存位置和并发原子操作对象、内存位置和并发一个对象无论是基础类型还是自定义类型,这个对象都会存储在一个或多个内存位置上。在多线程程序中,如果两个线程访问不同的内存位置,往往不会有什么问题。但当它们访问同一个内存位置时,如果该位置上的数据被更新了,那么就会产生条件竞争,这是多线程程序常见的问题。解决的方式就像之前所说的,使用互斥量来保护共享数据,同一时间只能有一个线程能够...原创 2020-03-21 17:54:44 · 298 阅读 · 0 评论 -
3.5 等待时间的应用
文章目录限定时间的方式互斥量的等待时间条件变量的等待时间期望值的等待时间限定时间的方式限定时间,有两种方式:1)明确延时的一个时间段:(_for 作为后缀)std::this_thread::sleep_for(std::chrono::milliseconds(3000));2)明确延时后的时间点:(_until 作为后缀)std::chrono::steady_clock::...原创 2020-03-20 23:38:31 · 323 阅读 · 0 评论 -
3.4 任务包装、promise 和 future
文章目录std::packaged_taskstd::packaged_task原创 2020-03-19 21:45:43 · 219 阅读 · 0 评论 -
3.3 async和future
文章目录创建一个异步任务向异步任务传递参数std::launch创建一个异步任务假设我们想在子线程中返回一个值给父线程,除了使用引用传参外,还有什么别的方法吗?当我们不着急获取一个计算的结果时,可以使用 std::async 来启动一个异步任务,让异步任务执行这个计算。计算结束后,std::async 会返回一个 std::future 对象,它保存着计算的结果,调用 get() 方法...原创 2020-03-19 21:32:30 · 292 阅读 · 0 评论 -
3.2 生产者消费者问题
文章目录轮询版条件变量版生产者消费者问题是在线程同步中的经典问题。下面慢慢来剖析它。轮询版这里,有一个全局的队列 q,一个生产者线程,一个消费者线程。我们都知道,在生产者消费者问题中,全局队列 q 是需要用互斥量保护起来的。对生产者来说,只要队列的容量 < 11,那么就试图获取锁,然后进行数据生产,生产完毕以后,释放锁,这是为了让消费者有机会持有锁并消费队列中的数据。对消费...原创 2020-03-19 18:27:48 · 167 阅读 · 0 评论 -
3.1 线程同步和条件变量
文章目录互斥和同步互斥和同步互斥和同步都是指某一个资源在某个时刻只能被一个访问者进行访问。互斥不限制访问者对资源的访问顺序。同步则是使用一定的机制来实现访问者对资源的有序访问。...原创 2020-03-17 15:16:35 · 160 阅读 · 0 评论 -
2.5 lazy initialization
文章目录保护共享数据的初始化过程std::call_oncestd::call_once 的替代方案保护共享数据的初始化过程lazy initialization (延迟初始化)在单线程的代码中是很常见的。譬如一个共享数据的初始化构建可能会消耗较多的资源,那么对它的每次操作都需要先对它进行检查,如果它已经被初始化了,那么就可以直接使用而不是重新再初始化它。例如,打开一个文件可能需要消耗...原创 2020-03-17 14:53:36 · 730 阅读 · 0 评论 -
2.4 灵活的unique_lock
文章目录std::unique_lockstd::defer_lock 参数lock_guard 和 unique_lock 的异同std::unique_lock前面我们学习了 std::lock_guard,现在,我们介绍一种更灵活的 std::unique_lock,其参数可以有std::adopt_lockstd::defer_lock 表示告诉 std::unique_l...原创 2020-03-16 22:45:42 · 199 阅读 · 0 评论 -
2.3 并发程序中的死锁
文章目录死锁的概念死锁的四个必要条件死锁实例std::lock避免死锁的建议死锁的概念死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。通常,死锁是由下面的原因产生的:争夺系统资源请求和释放资源的顺序不当死锁的四个必要条件1)互斥条件一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请...原创 2020-03-16 21:15:07 · 219 阅读 · 0 评论 -
2.2 并发程序中使用STL容器
文章目录STL 接口引发的条件竞争现在假设有一个双链表,为了让线程可以安全地删除某个节点。最简单的办法是用互斥量在添加和删除节点时保护整个链表,而不应该是只保护要删除节点以及它前后相邻的节点,这样往往会带来coding上的麻烦。STL 接口引发的条件竞争例如,STL中一个常见的模板类 stack,提供了下面的方法:push()pop()top()empty()size()...原创 2020-03-16 17:59:26 · 272 阅读 · 0 评论 -
2.1 线程间数据共享与互斥量
文章目录线程间的数据共享互斥量的概念互斥量应用std::lock_guard互斥量的设计准则互斥量的缺点线程间的数据共享当在线程间存在数据共享,分为两种情况:如果共享数据是只读的,一般不会出现什么问题,所有的线程都将获得同样的数据如果共享数据可写,那么如果某个或多个线程要对该共享数据进行修改,那么通常会出现数据不一致的问题。这就是在写多线程程序时经常发生的条件竞争现象,简直阔怕...原创 2020-03-16 17:46:10 · 463 阅读 · 0 评论 -
1.6 线程数和线程ID
获取硬件支持的并发线程数std::thread::hardware_concurrency(),一般其返回值是CPU核心的数量。当然,获取不到系统信息时,会返回0线程ID线程ID是每个线程独有的属性,可以通过两种方式获取:在当前线程中调用 std::this_thread::get_id()使用 std::thread 对象的 get_id() 方法,当没有跟过程函数关联时,它将返回0...原创 2020-03-16 12:21:44 · 207 阅读 · 0 评论 -
1.5 转移线程所有权
移动语义在讨论转移线程所有权之前,先来看之前提到的例子:之前我们说到,向线程过程函数传递参数,是值传递,如果想改为引用传递,那么改为:std::thread t1(func, std::ref(str));现在考虑一个问题,假如 str 不会再在主线程中使用了,为了避免数据竞争或者说无用的空间占用,我们可以使用移动语义来将 str 的所有权从主线程移动到子线程,然后去执行 func ...原创 2020-03-16 11:17:30 · 375 阅读 · 1 评论 -
1.4 线程结束和分离
前面我们已经学习了 join 和 detach 的使用方法。也就是在线程启动以后,我们需要明确到底是:主线程等待子线程结束?将子线程从主线程中分离出去,独立运行?无论是哪种形式,都必须要在 std::thread 对象销毁之前确定下来。否则,std::thread 对象销毁时会调用析构函数,进而 std::terminate() 。即使出现了异常,我们也应当确保线程能够 join 或...原创 2020-03-16 09:32:21 · 365 阅读 · 0 评论 -
1.3 花式创建线程
启动线程需要注意的问题在上一节,我们已经学会了最简单的线程初始化,用的是一个无参的函数来创建线程的。那么,我们还有别的线程启动方式吗?有的。下面举一个仿函数对象初始化线程的例子。我们知道,在C++中,有一个东西叫做仿函数,它本质上是一个类,只是重载了函数调用运算符。是可以用它的对象来初始化线程的在这种情况下,有两个需要注意的地方:A:提供的函数对象会复制到新线程的空间当中,B:...原创 2020-03-15 22:52:53 · 304 阅读 · 2 评论 -
1.2 第一个并发程序
从 hello world 开始我们开始学一门语言,都是从 hello world 开始的。这,是只有一个主线程的程序。第一个并发程序使用线程库,需要包含头文件,在该头文件中包含了管理线程的函数和类。#include <thread>我们知道,每个线程都有对应的线程过程函数,所以需要用一个线程过程函数来初始化线程。这样,就将原来的线程数变为了2,分别是主线程 ma...原创 2020-03-15 22:02:39 · 191 阅读 · 0 评论 -
1.1 并发的概念
计算机的并发假设有两个任务,每个任务被分成了大小相等的块:1)对于以前的单核计算机,其只能在某一时刻执行一个任务,但实际上每一秒进行了很多次的任务切换,也就是说任务并不是顺序进行的。这样的任务切换很快,人甚至还来不及感受到一个任务已经被挂起,而另一个任务已经被切换执行了,因此造成并发的假象。值得一提的是,在每次切换任务时会做一次上下文切换,保存当前的CPU状态和指令指针,调度以后加载新任...原创 2020-03-15 21:33:40 · 344 阅读 · 0 评论