C++11中的使用

原子库为细粒度的原子操作提供组件,允许无锁并发编程。涉及同一对象的每个原子操作,相对于任何其他原子操作是不可分的。原子对象不具有数据竞争(data race)。原子类型对象的主要特点就是从不同线程访问不会导致数据竞争。因此从不同线程访问某个原子对象是良性(well-defined)行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义(undifined)行为发生。

atomic是C++标准程序库中的一个头文件,定义了C++11标准中的一些表示线程、并发控制时原子操作的类与方法等。此头文件主要声明了两大类原子对象:std::atomic和std::atomic_flag,另外还声明了一套C风格的原子类型和与C兼容的原子操作的函数。在多线程并发执行时,原子操作是线程不会被打断的执行片段。一些程序设计更为注重性能和效率,需要开发lock-free的算法和数据结构,这就需要更为底层的原子操作与原子类型。原子类型对象的主要特点就是从不同线程并发访问是良性(well-defined)行为,不会导致竞争危害。与之相反,不做适当控制就并发访问非原子对象则会导致未定义(undifined)行为。

atomic_flag类:是一种简单的原子布尔类型,只支持两种操作:test_and_set(flag=true)和clear(flag=false)。跟std::atomic的其它所有特化类不同,它是锁无关的。结合std::atomic_flag::test_and_set()和std::atomic_flag::clear(),std::atomic_flag对象可以当作一个简单的自旋锁(spin lock)使用。atomic_flag只有默认构造函数,禁用拷贝构造函数,移动构造函数实际上也禁用。如果在初始化时没有明确使用宏ATOMIC_FLAG_INIT初始化,那么新创建的std::atomic_flag对象的状态是未指定的(unspecified),既没有被set也没有被clear;如果使用该宏初始化,该std::atomic_flag对象在创建时处于clear状态。

(1)、test_and_set:返回该std::atomic_flag对象当前状态,检查flag是否被设置,若被设置直接返回true,若没有设置则设置flag为true后再返回false。该函数是原子的。

(2)、clear:清除std::atomic_flag对象的标志位,即设置atomic_flag的值为false。

std::atomic类模板:std::atomic比std::atomic_flag功能更加完善。C++11标准库std::atomic提供了针对bool类型、整形(integral)和指针类型的特化实现。每个std::atomic模板的实例化和完全特化定义一个原子类型。若一个线程写入原子对象,同时另一个线程从它读取,则行为良好定义。而且,对原子对象的访问可以按std::memory_order所指定建立线程间同步,并排序非原子的内存访问。std::atomic可以以任何可平凡复制(Trivially Copyable)的类型T实例化。std::atomic既不可复制亦不可移动。

除了std::atomic和std::atomic_flag外,<atomic>还包括了基于std::atomic_flag类的C风格API和基于std::atomic类模板的C风格API。

与原子对象初始化相关的两个宏:

(1)、ATOMIC_VAR_INIT(val):初始化std::atomic对象。This macro expands to a token sequence suitable to initialize an atomic object (of static storage duration) with a value of val. This macro exists for compatibility with C implementations, in which it is used as a constructor-like function for(default-constructed) atomic objects; In C++, this initialization may be performed directly by the initialization constructor.

(2)、ATOMIC_FLAG_INIT:初始化std::atomic_flag对象。This macro is defined in such a way that it can be used to initialize an object of type atomic_flag to the clear state.

std::atomic:Objects of atomic types contain a value of a particular type (T). The main characteristic of atomic objects is that access to this contained value from different threads cannot cause data races (i.e., doing that is well-defined behavior, with accesses properly sequenced). Generally, for all other objects, the possibility of causing a data race for accessing the same object concurrently qualifies the operation as undefined behavior. Additionally, atomic objects have the ability to synchronize access to other non-atomic objects in their threads by specifying different memory orders.

std::atomic_flag:Atomic flags are boolean atomic objects that support two operations:test-and-set and clear.

下面是从其他文章中copy的<atomic>测试代码,详细内容介绍可以参考对应的reference:

#include "atomic.hpp"
#include <iostream>
#include <atomic>
#include <vector>
#include <thread>
#include <sstream>

namespace atomic {
/////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/atomic/
std::atomic<bool> ready(false);
// atomic_flag::atomic_flag: Constructs an atomic_flag object
// The atomic_flag is in an unspecified state on construction (either set or clear),
// unless it is explicitly initialized to ATOMIC_FLAG_INIT.
std::atomic_flag winner = ATOMIC_FLAG_INIT;

void count1m(int id)
{
	while (!ready) { std::this_thread::yield(); }      // wait for the ready signal
	for (volatile int i = 0; i < 1000000; ++i) {}          // go!, count to 1 million
	if (!winner.test_and_set()) { std::cout << "thread #" << id << " won!\n"; }
};

int test_atomic_atomic()
{
	// atomic::atomic: Constructs an atomic object
	std::vector<std::thread> threads;
	std::cout << "spawning 10 threads that count to 1 million...\n";
	for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(count1m, i));
	ready = true;
	for (auto& th : threads) th.join();

	return 0;
}

/////////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/compare_exchange_weak/
// a simple global linked list:
struct Node { int value; Node* next; };
std::atomic<Node*> list_head(nullptr);

void append(int val)
{     // append an element to the list
	Node* oldHead = list_head;
	Node* newNode = new Node{ val, oldHead };

	// what follows is equivalent to: list_head = newNode, but in a thread-safe way:
	while (!list_head.compare_exchange_weak(oldHead, newNode))
		newNode->next = oldHead;
}

int test_atomic_compare_exchange_weak()
{
	// atomic::compare_exchange_weak: Compares the contents of the atomic object‘s contained value with expected:
	// -if true, it replaces the contained value with val(like store).
	// - if false, it replaces expected with the contained value
	// spawn 10 threads to fill the linked list:
	std::vector<std::thread> threads;
	for (int i = 0; i<10; ++i) threads.push_back(std::thread(append, i));
	for (auto& th : threads) th.join();

	// print contents:
	for (Node* it = list_head; it != nullptr; it = it->next)
		std::cout << ‘ ‘ << it->value;
	std::cout << ‘\n‘;

	// cleanup:
	Node* it; while (it = list_head) { list_head = it->next; delete it; }

	return 0;
}

///////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/exchange/
std::atomic<bool> winner_(false);

void count1m_(int id)
{
	while (!ready) {}                  // wait for the ready signal
	for (int i = 0; i<1000000; ++i) {}   // go!, count to 1 million
	if (!winner_.exchange(true)) { std::cout << "thread #" << id << " won!\n"; }
};

int test_atomic_exchange()
{
	// atomic::exchange: Replaces the contained value by val and returns the value it had immediately before
	std::vector<std::thread> threads;
	std::cout << "spawning 10 threads that count to 1 million...\n";
	for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(count1m_, i));
	ready = true;
	for (auto& th : threads) th.join();

	return 0;
}

/////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/load/
std::atomic<int> foo(0);

void set_foo(int x)
{
	foo.store(x, std::memory_order_relaxed);     // set value atomically
}

void print_foo()
{
	int x;
	do {
		x = foo.load(std::memory_order_relaxed);  // get value atomically
	} while (x == 0);
	std::cout << "foo: " << x << ‘\n‘;
}

int test_atomic_load()
{
	// atomic::load: Returns the contained value.
	// The operation is atomic and follows the memory ordering specified by sync.
	std::thread first(print_foo);
	std::thread second(set_foo, 10);
	first.join();
	second.join();

	return 0;
}

////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/operator=/
std::atomic<int> foo_ = 0;

void set_foo_(int x)
{
	foo_ = x;
}

void print_foo_()
{
	while (foo_ == 0) {             // wait while foo_=0
		std::this_thread::yield();
	}
	std::cout << "foo_: " << foo_ << ‘\n‘;
}

int test_atomic_operator()
{
	// atomic::operator=: Replaces the stored value by val.
	// This operation is atomic and uses sequential consistency (memory_order_seq_cst).
	// To modify the value with a different memory ordering
	std::thread first(print_foo_);
	std::thread second(set_foo_, 10);
	first.join();
	second.join();

	return 0;
}

///////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic/store/
int test_atomic_store()
{
	// atomic::store: Replaces the contained value with val.
	// The operation is atomic and follows the memory ordering specified by sync.
	std::thread first(print_foo);
	std::thread second(set_foo, 10);
	first.join();
	second.join();

	return 0;
}

/////////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/atomic/atomic_flag/clear/
std::atomic_flag lock_stream = ATOMIC_FLAG_INIT;
std::stringstream stream;

void append_number(int x)
{
	while (lock_stream.test_and_set()) {}
	stream << "thread #" << x << ‘\n‘;
	lock_stream.clear();
}

int test_atomic_flag_atomic_clear()
{
	// atomic_flag::clear: Clears the atomic_flag (i.e., sets it to false)
	//Clearing the atomic_flag makes the next call to member atomic_flag::test_and_set on this object return false.
	// The operation is atomic and follows the memory ordering specified by sync.

	// atomic_flag::test_and_set: Sets the atomic_flag and returns whether it was already set immediately before the call
	// The entire operation is atomic (an atomic read-modify-write operation): the value is not affected by other threads
	// between the instant its value is read (to be returned) and the moment it is modified by this function.
	std::vector<std::thread> threads;
	for (int i = 1; i <= 10; ++i) threads.push_back(std::thread(append_number, i));
	for (auto& th : threads) th.join();

	std::cout << stream.str();
	return 0;
}

} // namespace atomic

GitHubhttps://github.com/fengbingchun/Messy_Test

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

原文地址:https://www.cnblogs.com/xkiwnchwhd/p/10317946.html

时间: 2024-11-18 16:56:15

C++11中的使用的相关文章

C++11中多线程库

一.linux 线程同步 线程是在操作系统层面支持的,所以多线程的学习建议还是先找一本linux系统编程类的书,了解linux提供多线程的API.完全完全使用系统调用编写多线程程序是痛苦,现在也有很多封装好的多线程库,但是了解多线程系统对学习编写多线程程序非常有好处.总的来说linux提供了四类系统用于多程序程序,分别线程的创建.销毁(thread),用于线程同步的(互斥量(mutex).条件量(cond),信号量(sem)). 互斥量通过锁的机制实现线程间的同步.互斥量是一种特殊的变量,可以对

XenApp/XenDesktop 7.11中对于视频、图片、文字的优化的说明

在桌面虚拟化这个技术门类中,市面上一共主流有以下几种协议: Citrix的ICA/HDX协议 Teradici公司的PCoIP(VMware Horzion中主要使用的协议之一) 微软公司的RDP RedHat公司的spice 以及近两年我们能接触到的 VMware公司的Blast(VMware在Horizion 6版本以后开始提供的协议,有逐步替代PCoIP的趋势) 华为的HDP 但是无论怎么墙头变换大王旗,Citrix的ICA/HDX协议可以说多年来一直都是行业最为优秀的企业级远程交付协议.

【转载】C++ 11中的右值引用

本篇随笔为转载,原博地址如下:http://www.cnblogs.com/TianFang/archive/2013/01/26/2878356.html 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream>    #include <vector>    using namespace std; class obj    {    public :        obj() { cout <&l

C++11中uniform initialization和initializer_list

C++11中出现了uniform initialization的概念: int a1 = {1};//ok int a2 = {1.0};//错误,必须收缩转换 int array1[] = {1,2,3,4};//ok int arrya2[] = {1.0,2.0,3.0,4.0};//ok 注意a2的初始化错误和array2的正确对比.一方面uniform initialization要求初始化的类型必须是一致的,但一方面新的C++标准必须兼容C++98,而在C++98中array2的初始

C++11中once_flag,call_once实现分析

本文的分析基于llvm的libc++,而不是gun的libstdc++,因为libstdc++的代码里太多宏了,看起来蛋疼. 在多线程编程中,有一个常见的情景是某个任务只需要执行一次.在C++11中提供了很方便的辅助类once_flag,call_once. 声明 首先来看一下once_flag和call_once的声明: struct once_flag { constexpr once_flag() noexcept; once_flag(const once_flag&) = delete

C++11中的指针空值nullptr

时间:2014.05.07 地点:基地 ----------------------------------------------------------------------------- 一.为什么要有指针空值nullptr 在良好的编码习惯中,声明一个指针并对其进行初始化非常重要,未初始化的悬挂指针常导致一些难以调试的错误.往常,我们常这样初始化指针变量: int* my_ptr1=0; int* my_ptr2=NULL; 但我们知道,NULL其实是一个宏定义,字面常量为0,即上述两

C++ 11 中的右值引用

C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream>    #include <vector>    using namespace std; class obj    {    public :        obj() { cout << ">> create obj " << endl; }        obj(c

在c++11中你最吃惊的新feature是什么?

对我来说,我最吃惊居然把对于多线程的支持加到标准中了.真的想不明白,对于c++这样一种语言,怎么会加进这个东西. 1. 因为各个平台的不同,对于多线程的支持会有许多平台独有的特色,这样c++标准的定义必然会受到很大限制. 2. 各个平台对于多线程的支持已经形成了各自的标准,比如pthread,或是windows上的标准api,现在去推c++的多线程标准,有意义吗?是不是太晚了? 但是仍然看到c++11中加入了很多很棒的feature.相信其中很多的feature会在以后的c++编程中大行其道.

C++11中智能指针的原理、使用、实现

目录 理解智能指针的原理 智能指针的使用 智能指针的设计和实现 1.智能指针的作用 C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理.程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,C++11中引入了智能指针的概念,方便管理堆内存.使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存. 理解智能指针需要从下面三个层次: 从较浅的层面看,智能指针是利用了一种叫做RAII(资

正则表达式简介及在C++11中的简单使用

正则表达式(regular expression)是计算机科学中的一个概念,又称规则表达式,通常简写为regex.regexp.RE.regexps.regexes.regexen. 正则表达式是一种文本模式.正则表达式是强大.便捷.高效的文本处理工具.正则表达式本身,加上如同一门袖珍编程语言的通用模式表示法(general pattern notation),赋予使用者描述和分析文本的能力.配合上特定工具提供的额外支持,正则表达式能够添加.删除.分离.叠加.插入和修整各种类型的文本和数据. 完