c++多线程基础四-- 原子操作

1 call_once使用

函数模板,该函数的第一个参数为标记,第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。
call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态。

once_flag g_flag;
class Singelton
{
public:
    static void CreateInstance()//call_once保证其只被调用一次
    {
        instance = new Singelton;
    }
    //两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
	static Singelton * getInstance() {
         call_once(g_flag, CreateInstance);
         return instance;
	}
private:
	Singelton() {}
	static Singelton *instance;
};
Singelton * Singelton::instance = NULL;

2 原子操作

大家可以把原子操作理解成一种:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式。

原子操作:在多线程中不会被打断的程序执行片段。

从效率上来说,原子操作要比互斥量的方式效率要高。

互斥量的加锁一般是针对一个代码段,而原子操作针对的一般都是一个变量。

原子操作,一般都是指“不可分割的操作”;也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态。

2.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 状态。

atomic_flag使用介绍

2.2 std::atomic

std::atomic 是模板类,一个模板类型为 T 的原子对象中封装了一个类型为 T 的值。

template struct atomic;
原子类型对象的主要特点就是从不同线程访问不会导致数据竞争(data race)。因此从不同线程访问某个原子对象是良性 (well-defined) 行为,而通常对于非原子类型而言,并发访问某个对象(如果不做任何同步操作)会导致未定义 (undifined) 行为发生。
使用实例

std::atomic<int> count(0);

注意:一般atomic原子操作,针对++,–,+=,-=,&=,|=,^=是支持的,其他操作不一定支持
代码示例:

#include <iostream>             // std::cout
#include <atomic>               // std::atomic
#include <thread>               // std::thread, std::this_thread::yield
 
std::atomic <int> foo = 0;
 
void set_foo(int x)
{
    foo = x; // 调用 std::atomic::operator=().
}
 
void print_foo()
{
    while (foo == 0) { // wait while foo == 0
        std::this_thread::yield();
    }
    std::cout << "foo: " << foo << '\n';
}
 
int main()
{
    std::thread first(print_foo);
    std::thread second(set_foo, 10);
    first.join();
    second.join();
    return 0;
}

atomic使用

posted @ 2021-01-16 18:09  lihaihui199102  阅读(372)  评论(0)    收藏  举报