并发编程
文章平均质量分 72
yamingwu
这个作者很懒,什么都没留下…
展开
-
[C++11 并发编程] 09 - 在初始化阶段保护共享数据
除了mutex,还有一些其它的方法在特定的场景下对共享数据进行保护,首先,我们来看看如何在初始化阶段保护数据。有些时候,只需要在初始化阶段对共享数据进行保护,这样的数据可能在创建好之后是只读的,这样就没有同步问题。也可能在操作数据时,已经有了必要的保护。这样如何还是使用mutex来保护初始化过程,就没有太大必要,也比较影响性能。C++标准提供了一个纯粹用于在初始化阶段保护共享数据的机制。假原创 2015-08-22 17:55:45 · 1026 阅读 · 0 评论 -
[C++11 并发编程] 17 超时等待 - time_point
模版类std::chrono::time_point用于表示一个时间点。我们需要为时间点指定参考时钟(clock )和相对于参考时钟步进值。time point的值实际上就是某个时间点到参考时钟的起始时间(比如格林威治标准时间 1970 年 1 月 1 日的00:00:00.000)的时间长度。这个长度是时钟步进的倍数。其关键成员如下:Member typesM原创 2015-09-10 18:04:53 · 2441 阅读 · 1 评论 -
[C++11 并发编程] 17 超时等待 - clock和duration
之前我们看到的所有等待机制都是不会超时的,也就是说,等待某个同步事件的线程会一直挂起。有些情况下,我们希望设置一个最长等待时间,使得程序可以继续与用户进行交互,使得用户可以取消这个操作。我们先来看看C++11提供的时钟类clock:clockclock提供了如下四种信息:当前时间存放从clock获取到的时间的类型时钟每个tick的周期每个tick的周期是否固定,固定则为“ste原创 2015-09-09 14:59:32 · 6103 阅读 · 0 评论 -
[C++11 并发编程] 07 - Mutex 死锁
假设有两个线程,在执行某些操作时,都需要锁定一对mutex,线程A锁定了mutex A,而线程B锁定了额mutex B,它们都在等待对方释放另一个mutex,这就会导致这两个线程都无法继续执行。这种情况就是死锁。避免死锁最简单的方法是总是以相同的顺序对两个mutex进行锁定,比如总是在锁定mutex B之前锁定mutex A,就永远都不会死锁。假设有一个操作要交换同一个类的两个实例的内容,原创 2015-08-15 16:08:58 · 5485 阅读 · 0 评论 -
[C++11 并发编程] 02 - join
1. 等待线程完成若不等待线程完成,我们就需要确保该线程访问的数据都是有效的,直到该线程完成为止。比如如下代码,线程函数持有局部变量的指针或引用,当函数退出时,线程尚未执行完成。#include #include // 线程持有局部变量的指针struct func{ int *i; func(int *i_) : i(i_){ } void operator()(原创 2015-08-03 21:20:28 · 2242 阅读 · 0 评论 -
[C++11 并发编程] 16 在期望中保存异常
如果在异步线程中发生了异常,等待期望的线程如何才能知道并且正确的处理异常呢?假设有如下所示的一个求平方根的函数:double square_root(double x){ if(x<0) { throw std::out_of_range(“x<0”); }return sqrt(x);}原创 2015-08-31 23:05:02 · 934 阅读 · 0 评论 -
[C++11 并发编程] 01 - Hello World
C++11标准支持了并发,其中包含了线程管理,共享资源保护,线程间同步操作和底层原子操作等功能。我们先通过一个简单的示例看看C++11标准的多线程程序是什么样的。#include #include // 引用用于管理线程的类的头文件using namespace std;// 线程的入口函数,程序将在新创建的线程中打印logvoid hello(){ cout << "Hel原创 2015-06-04 14:16:23 · 1412 阅读 · 0 评论 -
[C++11 并发编程] 06 - Mutex race condition
上一节中介绍了mutex的基本使用方法,使用mutex来保护共享数据并不能解决race condition带来的问题,假如我们有一个堆栈数据结构类似于std::stack它提供了5个基本操作push(),pop(),top(),empty(),和size()。这里的top()操作返回栈顶元素的拷贝,这样我们就可以使用一个mutex来保护栈内部的数据。但是race codition情况下,虽然使用m原创 2015-08-14 21:52:20 · 1415 阅读 · 0 评论 -
[C++11 并发编程] 04 - 动态选择并发线程的数量
C++标准模板库提供了一个辅助函数 - std::thread::hardware_concurrency(),通过这个函数,我们可以获取应用程序可以真正并发执行的线程数量。下面这个例子,实现了一个并发版本的std::accumulate,它将工作拆分到多个线程中,为了避免过多线程带来的开销,程序指定了每个线程处理数据的最小数量。头文件和求和操作:#include #include #原创 2015-08-08 10:53:22 · 2821 阅读 · 0 评论 -
[C++11 并发编程] 03 - 向线程传递参数
我们可以通过std::thread的构造函数向线程传递参数,但是默认情况下,这些参数的拷贝会被传递到线程内部,即使参数申明为引用,也是如此:void f(int i,std::string const& s);std::thread t(f,3,"hello");如上面例子所示,创建了一个线程关联到t,它会调用f(3, "hello"),虽然f的第二个参数类型为std::string,但是实原创 2015-08-07 18:10:57 · 8006 阅读 · 3 评论 -
[C++11 并发编程] 05 - Mutex 基本操作
Mutex是C++中最常见的数据保护机制之一,在访问一块共享数据前,lock mutex,在完成对数据的访问后,unlock mutex。线程库当一个特定mutex被某个线程lock后,其它尝试lock同一个mutex的线程都会被挂起指导这个mutex被unlock。这就保证了所有线程看到的数据都是完整的,不会被修改了一部分的数据。在C++中,通常我们通过创建std::mutex的实例原创 2015-08-09 20:21:29 · 2444 阅读 · 0 评论 -
[C++11 并发编程] 15 承诺promise
假设有一个应用程序应用程序用于处理大量的网络连接,通常我们会为每一个连接创建单独的处理线程。当线程数量较少时,这样是可行的,但是随着连接数量的增加,大量的线程需要消耗大量的系统资源。这样,使用较少的线程,每个线程处理多个连接更为合适。std::promise提供了一个设置值的机制(类型T),通过与之关联的期望对象可以获取到被设置的值。std::promise/std::future一起配合,等原创 2015-08-28 22:34:58 · 2731 阅读 · 0 评论 -
[C++11 并发编程] 14 关联任务与期望
std::packaged_task对象被触发时,它将调用关联的函数和可调用对象使得期望被满足,并将返回值填入期望关联的数据之中。这个可以用于构建线程池,也可以用于任务管理(每个任务在各自的线程中执行或所有任务顺序的在一个后台线程中执行)。如果一个大的操作可以被拆分为多个子任务,每个子任务就可以被放入一个std::packaged_task实例打交道而不是与具体的函数打交道。std::pack原创 2015-08-28 00:41:46 · 1437 阅读 · 0 评论 -
[C++11 并发编程] 13 使用期望等待一次性事件
C++标准库使用期望(future)来支持一次性事件的等待。要等待某种一次性事件的线程可以获取一个代表该该事件的期望。这个线程可以每隔一段事件周期性的查询这个期望。此外,这个线程也可以继续做其它的处理,直到需要等待这个一次性事件才被挂起。通过期望还可以可以传递数据。C++标准库提供了两种期望unique future(std::future),都声明在库头文件中。std::future实例只能原创 2015-08-27 21:02:32 · 2054 阅读 · 0 评论 -
[C++11 并发编程] 12 使用条件变量创建线程间安全的队列
之前有一节中,我们使用mutex实现了一个线程间安全的堆栈。这一节,我们使用条件变量来实现一个线程间安全的队列。标准库中的std::queuetemplate >class queue {public: explicit queue(const Container&); explicit queue(Container&& = Container()); qu原创 2015-08-26 21:28:01 · 1153 阅读 · 0 评论 -
[C++11 并发编程] 11 - 线程间同步 - 等待一个消息或某种条件
上一节,我们了解了如何对线程之间的共享资源进行保护的方法。但是,有些时候,我们需要在线程之间进行同步操作。一个线程等待另一个线程完成某项工作后,再继续自己的工作。比如,某个线程需要等待一个消息,或者某个条件变成true。接下来几节,我们会看到如何使用C++标准库来做到线程间同步。等待另一个线程完成的方法有如下几种:一个线程不停地查询某个被mutex保护的贡献数据区中的标志的状态。另原创 2015-08-26 18:05:03 · 13182 阅读 · 0 评论 -
[C++11 并发编程] 10 - 对极少修改的数据进行保护
假设有一个用于进行域名解析的DNS缓存数据,在大多数情况下,DNS数据很少会改变。当用户访问新的网站时,新的DNS信息才会被自动添加到这个转换表之中。虽然对这个数据的修改很少发生,但是在多个线程读取数据时,有线程要修改数据,仍然会导致读取线程读到错误的数据。我们需要使用某种方式来对读写操作进行保护。使用前面几节用到的std::mutex可以达到保护数据完整性的效果,但是效率太低。因为大多数线程原创 2015-08-24 23:42:04 · 959 阅读 · 0 评论 -
[C++11 并发编程] 08 - Mutex std::unique_lock
相对于std::lock_guard来说,std::unique_lock更加灵活,std::unique_lock不拥有与其关联的mutex。构造函数的第二个参数可以指定为std::defer_lock,这样表示在构造unique_lock时,传入的mutex保持unlock状态。然后通过调用std::unique_lock对象的lock()方法或者将将std::unique_lock对象传入s原创 2015-08-21 21:39:23 · 8916 阅读 · 0 评论