C11原子类型如何使用答案在这里,请

白癜风袪白 http://pf.39.net/bdfyy/bdflx/190322/6985653.html

以前程序运行的时候,都是单线程,顺序执行,不需要考虑并发,但是随着科技的发展,对性能提出了更高的要求,多线程的出现也给单个进程运行的并发提供了基础。虽然程序支持了并发操作,提高了程序的响应速度,增强了用户的体验感,但是同时也给程序员的开发工作带来了难度,需要考虑并发操作时的许多问题,特别是多个线程对共享资源的访问,如果控制不好,就会造成程序的运行没法按照预期的效果执行。

所谓的原子操作,就是多线程下“最小并且不可并行化”的操作。而C++11提供了原子类型,这很大程度上简化程序员对并发操作的难度。

本文首先从posix标准的pthread库提供的互斥锁开始介绍早期控制多线程并发的操作方式,接着再重点说明C++11提供的内置原子类型以及模版原子类型的用法,最后再简单介绍几个内存模型的含义。

一、poxis互斥锁

早期实现原子操作,可以借助posix标准提供的互斥锁来实现粗力度的互斥。这里的粗力度是区别于C++11的内存模型来说的。我们来看下poxis互斥锁的例子。

测试代码启动了两个线程对全局变量g_ll_total进行自增操作,为了保证g_ll_total的原子性,对全局变量g_ll_total修改之前进行加锁pthread_mutex_lock,修改之后解锁pthread_mutex_unlock。

运行之后的输出结果如下,其结果是正确的。从上面的例子看,每次对共享变量的修改,都要进行加锁解锁的操作,同时程序员还要注意管理互斥锁,这无疑增加了负担。

二、内置原子类型

C++11提供了原子类型,分别有内置的原子类型和模版原子类型。我们看下使用内置的原子类型来实现上面相同的功能。

上面的例子中,我们使用了内置原子类型atomic_llong,不需要对共享变量进行加解锁的操作,但是线程却能够对变量g_all_total正确的访问。

C++11支持的内置原子类型如下表所示

再来看下C++11的内置原子类型基本操作的例子。既可以定义atomic_int类型的变量,然后通过等于进行赋值,也可以在定义atomic_int类型的变量之后通过大括号来直接进行赋值。

三、模版原子类型

C++11除了提供内置的原子类型,更加通用使用方法是类模版的原子类型,通过该类模版,可以自定义需要的原子类型。其使用格式如下,声明类型为T的原子变量t,多线程对t的访问操作就能够保障正确性。

下面通过例子来说明其使用方法。类模版的定义与内置原子类型的定义基本相似,但是注意不能使用已经定义的原子类型去初始化新的原子类型。这是因为标准不允许原子类型进行拷贝构造、移动构造等操作。

但是可以使用模版类型变量来初始化其模版参数类型T,比如下面的例子中,我们定义了类型为std::atomicint的变量atomic_number1,然后将其赋值给类型为int的变量i_number3。原子类型也提供了load接口来获取原子类型的值。

类模版原子类型也提供了store的写操作,来将数据写入原子类型变量中,store的操作等同于=赋值操作。

C++11支持的操作如下表所示,atomic-integral-type和integral-type指整型的原子类型,class-type是自定义类型。

C++11提供了std::atomic_flag是无锁的,即线程对其的访问是不需要加锁。它支持两个接口test_and_set和clear,test_and_set是修改atomic_flag为true,然后返回它的旧值。test_and_set的默认参数是std::memory_order_seq_cst,表示顺序一致性,这涉及到内存模型的知识,后面将会进行简单说明。只需要记住的一点是,所有的原子类型都是采用该默认值。

通过std::atomic_flag可以实现线程之间的同步,下面的例子中,首先定义了atomic_flag类型的变量flg_lock,并初始化为ATOMIC_FLAG_INIT。然后再实现两个线程的执行函数,第一个函数aFunc,通过调用test_and_set来等待获取atomic_flag的值,如果返回false,那么往下执行代码,如果返回true,那么继续等待;第二个函数bFunc则执行atomic_flag的接口clear来将其设置为false。最后编写测试代码,程序开始的时候调用test_and_set,目的是将flg_lock设置为true,然后再启动两个线程。这样就实现了线程1等待线程2的通知之后,才继续往下执行的功能。

四、内存模型含义

C++11的原子类型提供的操作,大部分都使用std::memory_order作为参数,memory_order是一个枚举类型,其定义如下所示。

memory_order枚举类型的含义如下

如果不指定参数,那么原子类型的默认值是memory_order_seq_cst,即顺序一致性。但是这会影响程序的并发性能。因此,在实际程序开发过程中,需要根据具体场景来来设置memory_order值。从上表的描述中,可以看出memory_order_acquire是针对当前线程的读操作,而memory_order_release是针对当前线程的写操作。特别需要注意的是memory_order_consume是针对当前线程的本原子,但是不影响当前线程的其他原子。

五、总结

至此,已经将原子类型的基本知识及其使用介绍完成。本文主要介绍了内置原子类型和类模版原子类型,另外还简单介绍了内存模型的知识,关于内存模型只是说明了其概念。深入的介绍,计划后续通过新的章节来总结。




转载请注明:http://www.aierlanlan.com/tzrz/1837.html

  • 上一篇文章:
  •   
  • 下一篇文章: