c++11 atomic 之 atomic_flag 使用
c++11 引入了原子操作部分,为无锁编程提供了极大的便利,本系列博文主要涉及一下几个方面
- atomic_flag:c++11
<atomic>
头文件中最简单的原子类型: 。atomic_flag 一种简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。 - atomic 对 bool char int long,指针等数据类型进行原子操作,原子操作不包括浮点数类型以及复合数据类型,主要介绍相关的接收以及使用
- atomic的c-style接口 :提供相同语义但是不使用诸如:template reference 和member fucntion 等c++特性,整个atomic接口有一个C-style 对等品,成为C standard的一份补充,C-style接口一般适用于需要在C和C++之间保持兼容的代码身上 。
- atomic 底层内存布局的相关内容 :涉及程序在指令运行顺序的相关问题(暂不进行详细研究)
本博文主要介绍atomic_flag的使用
头文件中最简单的原子类型: atomic_flag。atomic_flag 一种简单的原子布尔类型,只支持两种操作,test-and-set 和 clear。
1、构造函数
std::atomic_flag 构造函数
std::atomic_flag 构造函数如下:
atomic_flag() noexcept = default;
atomic_flag (const atomic_flag&T) = delete;
std::atomic_flag 只有默认构造函数,拷贝构造函数已被禁用,因此不能从其他的 std::atomic_flag 对象构造一个新的 std::atomic_flag 对象。
如果在初始化时没有明确使用 ATOMIC_FLAG_INIT初始化,那么新创建的 std::atomic_flag 对象的状态是未指定的(unspecified)(既没有被 set 也没有被 clear。)另外,atomic_flag不能被拷贝,也不能 move 赋值。
ATOMIC_FLAG_INIT: 如果某个 std::atomic_flag 对象使用该宏初始化,那么可以保证该 std::atomic_flag 对象在创建时处于 clear 状态。
2、std::atomic_flag::test_and_set 介绍
std::atomic_flag 的 test_and_set 函数原型如下:
bool test_and_set (memory_order sync = memory_order_seq_cst) volatile noexcept;
bool test_and_set (memory_order sync = memory_order_seq_cst) noexcept;
test_and_set() 函数检查 std::atomic_flag 标志,如果 std::atomic_flag 之前没有被设置过,则设置 std::atomic_flag 的标志,并返回先前该 std::atomic_flag 对象是否被设置过,如果之前 std::atomic_flag 对象已被设置,则返回 true,否则返回 false。
test-and-set 操作是原子的(因此 test-and-set 是原子 read-modify-write (RMW)操作)。
2、std::atomic_flag::clear() 介绍
清除 std::atomic_flag 对象的标志位,即设置 atomic_flag 的值为 false。clear 函数原型如下:
void clear (memory_order sync = memory_order_seq_cst) volatile noexcept;
void clear (memory_order sync = memory_order_seq_cst) noexcept;
清除 std::atomic_flag 标志使得下一次调用 std::atomic_flag::test_and_set 返回 false。
3、使用例子
利用atomic_flag 实现多个线程同时对一个变量进行++的操作
将atomic_flag 当作一个锁来使用
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
#include <iostream>
#include <atomic>
int global_int = 0;
// 进行初始化
std::atomic_flag mutex = ATOMIC_FLAG_INIT;
void* thread_func(void *arg)
{
int i = 0;
while(i < 1000000)
{
if(!mutex.test_and_set())
{
global_int++;
i++;
mutex.clear();
}
else
{
/* code */
}
}
}
int main()
{
struct timeval start_time, end_time;
//运行计时开始
gettimeofday(&start_time, NULL);
int proc, i;
proc = sysconf(_SC_NPROCESSORS_ONLN); // 获取cpu核数
if (proc < 0)
{
exit(1);
}
pthread_t *threadId = (pthread_t *)malloc(proc*sizeof(pthread_t));
for (i = 0; i < proc; i++)
{
pthread_create(&threadId[i], NULL, thread_func, NULL);
}
for (i = 0; i < proc; i++)
{
pthread_join(threadId[i], NULL);
}
//运行计时结束
gettimeofday(&end_time, NULL);
//打印相关信息
printf("thread number = %d global_int = %d cost time msecond = %ld\n",
proc, global_int,
(long)((end_time.tv_sec - start_time.tv_sec)*1000 + (end_time.tv_usec - start_time.tv_usec)/1000));
}
编译运行如下:
g++ -o atomic atomic_flag.cpp -lpthread
./atomic
thread number = 2 global_int = 2000000 cost time msecond = 87