C++0x概览:多线程(2)

数据保护

同许多线程API一样,C++0x用互斥来保护共享数据。有四种互斥类型:

Non-recursive (std::mutex)

Recursive (std::recursive_mutex)

允许锁超时的non-recursive (std::timed_mutex)

允许锁超时的recursive (std::recursive_timed_mutex)

如果你试图在一个线程上锁(lock)一个non-recursive mutex两次而当中没有unlock它的话,会产生未知结果。递归recur6sive mutex只是增加锁的计数,因此必须确保你unlock和lock的次数相同,其他线程才可能锁这个mutex。

通常我们用模板类std::unique_lock<>和std::lock_guard<>来lock和unlock一个mutex。这些类在构造函数中lock一个mutex,在析构函数中unlock它。因此,如果你用的是局部变量,你的mutex会在退出作用域时自动被unlock。

std::mutex m;
  my_class data;
  void foo()
  {
    std::lock_guard<std::mutex> lk(m);
    process(data);
}  // mutex unlocked here

std::lock_guard只能像上面这样使用。而std::unique_lock允许延迟lock、设置超时,以及在对象销毁之前unlock。如果你选择std::timed_mutex来设置锁超时的话,那需要使用std::unique_lock:

std::timed_mutex m;
  my_class data;
  void foo()
  {
    std::unique_lock<std::timed_mutex>
      lk(m,std::chrono::milliseconds(3)); // wait up to 3ms
    if(lk) // if we got the lock, access the data
      process(data);
}  // mutex unlocked here

由于这些lock类是模板,因此他们可以用于所有标准的mutex类型,以及提供了lock()和unlock()函数的扩展类型。

避免死锁

有时候,我们需要锁多个mutex。如果控制不力,可能导致死锁(deadlock):两个线程都试图锁相同的mutex,每个线程都锁住一个mutex,而等待另外一个线程释放其他的mutex。C++0x考虑到了这个问题,你可以使用std::lock函数来一次锁住多个mutex,而不必冒着死锁的危险来一个一个地锁:

struct X
  {
    std::mutex m;
    int a;
    std::string b;
  };
  void foo(X& a,X& b)
  {
    std::unique_lock<std::mutex> lock_a(a.m,std::defer_lock);
    std::unique_lock<std::mutex> lock_b(b.m,std::defer_lock);
    std::lock(lock_a,lock_b);
    // do something with the internals of a and b
  }

在上面的例子中,如果你不使用std::lock的话,将很可能导致死锁(如一个线程执行foo(x,y), 另一个执行foo(y,x))。加上std::lock后,则是安全的。

时间: 2024-09-22 03:10:11

C++0x概览:多线程(2)的相关文章

C++0x概览:多线程(1)

++ 0x 标准将增加对多线程的支持.以后所有的编译器都必须遵循新标准中对多线程的规定,这将会给不同平台上程序的移植带来很大的方便. 让我们先来看看std::thread类,它负责管理线程的执行过程. 启动线程 我们创建一个std::thread类的实例来启动一个新线程,用一个线程函数作为构造函数的参数.如 void do_work(); std::thread t(do_work); std::thread类也接受一个函数对象作为参数. class do_work { public: void

C++0x概览:多线程(3)

在初始化时保护数据 如果你的数据需要在初始化时被保护,就不能再使用mutex了.因为在初始化结束后,这会引起不必要的同步.C++0x提供了很多方法来在初始化时保护数据. 1)假定你的构造函数是用constexpr关键字声明并且满足常量初始化的条件.在这种情况下,一个静态存储区的对象在静态初始阶段会确保在其他代码运行之前被初始化.对于std::mutex来说,这是最佳选择,因为它消除了全局mutex初始化时产生紊乱的可能性. class my_class { int i; public: cons

线程基础之JAVA和C++0x的特性

译文连接   译文地址  译者:衣着时   校对:丁一    (有兴趣参与试译或校对的同学,请加入并发网试译者QQ群:369468545) JAVA特性 JAVA线程通常是一个带有run()方法的java.lang.Thread的子类,然后调用这个子类对象的start()方法.我们之前定义过,数据竞争是因为两个线程同时访问内存单元,在JAVA中,内存单元是一个对象字段或数组元素. 由于JAVA旨在支持运行不受信任代码作为受信任的应用程序的一部分,必须限制不受信任代码的数据争用造成的破坏.因此不允

Optimizeit Thread Debugger概览

debug Optimizeit Thread Debugger概览本文通过介绍Optimizeit Thread Debugger的一些主要特征来使你对它有个简要的了解.如果想要了解更多的信息,请查看Optimizeit Thread Debugger用户手册,也可以从Optimizeit Thread Debugger单击主菜单info|help来查看所有的使用文档.使用中有何问题,请随时与Borland Technical Support联系.测试java程序Optimizeit Thre

iphone中如何进行多线程编程

  多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美.这篇文章主要从线程创建与启动.线程的同步与锁.线程的交互.线程池等等四个方面简单的讲解一下iphone中的多线程编程. 一.线程创建与启动 线程创建主要有二种方式: - (id)init; // designated initializer - (id)initWithTarget:(id)target selector:(SEL)selector ob

iOS开发系列—Objective-C之基础概览

概览 前面我们已经用了几章内容进行C语言介绍,当然要通过几篇文章完整的介绍C语言的知识是不太现实的,例如C语言的文件操作.内存申请等我们都没有重点介绍,当然核心知识点基本都已经提到了,后面有时间我们会继续扩充.今天我们正式开始学习Objective-C,以后简称"ObjC",ObjC是在C语言的基础上加上了一层面向对象的特性,它完全兼容C语言,甚至可以混写C++.它是Mac OS X和IOS的主要开发语言,从IOS发布之后可以说ObjC的地位呈直线上升趋势,当前ObjC已经是仅次于C语

关于Linux下的多线程

一.线程的创建 头文件 #include <pthread.h> 函数声明 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 在一个线程中调用pthread_create函数创建新的线程后,当前线程从pthread_create处继续往下执行,start_routine为新创建线程的入口函数,start_routine函数接

Java 性能调优指南之 Java 集合概览

[编者按]本文作者为拥有十年金融软件开发经验的 Mikhail Vorontsov,文章主要概览了所有标准 Java 集合类型.文章系国内 ITOM 管理平台 OneAPM 编译呈现,以下为正文: 本文将概览所有标准的 Java 集合类型.我们将按照它们可区分的属性与主要用例进行分类.除此之外,我们还将穷举在不同集合类型之间进行数据转换的方法. 数组(Arrays) 数组是 Java 语言内置的唯一集合类型,尤其擅长处理预先知道数量上限的元素集.java.util.Arrays 包含了许多用于处

《Spark官方文档》集群模式概览

Spark 1.6.0  译者:dlbrant 集群模式概览 本文简要描述了Spark在集群中各个组件如何运行.想了解如何在集群中启动Spark应用,请参考application submission guide . 组件 Spark应用在集群上运行时,包括了多个独立的进程,这些进程之间通过你的主程序(也叫作驱动器,即:driver)中的SparkContext对象来进行协调. 特别要指出的是,SparkContext能与多种集群管理器通信(包括:Spark独立部署时自带的集群管理器,Mesos