c++11 atomic 之 atomic_flag 使用

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

参考

C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)

发布了67 篇原创文章 · 获赞 15 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/wanxuexiang/article/details/104274876