C++11特性(13):原子操作及原子数据类型(1)

#include <iostream>
#include <thread>
#include <atomic>     //C++11新头文件 for  atomic_***原子数据类型
#include <windows.h> // for Sleep
 
//原子操作及原子数据类型
//原子数据类型:std::atomic_***
//C11的头文件<cstdatomic>简单的定义了对应于内置类型的原子类型
/*
     atomic_bool  -----> bool
     atomic_char  -----> char
     atomic_schar -----> signed char
     atomic_uchar -----> unsigned char
     atomic_int  -----> int
     atomic_uint  -----> unsigned int
     atomic_short -----> short
     atomic_ushort -----> unsigned short
     atomic_long  -----> long
     atomic_ulong -----> unsigned long
     atomic_llong -----> long long
     atomic_ullong -----> unsigned long long
     atomic_char16_t -----> char16_t
     atomic_char32_t ----->  char32_t
     atomic_wchar_t -----> wchar_t
 
     如果C11需要定义原子的自定义类型,需要使用C11的新关键字_Atomic来完成
     -----------------------------------------------------
     C++11的<atomic>头文件除了基本的原子数据类型,还定义了std::atomic类模板std::atomic<T>
*/
 
std::atomic_llong total{ 0 };
void fun()
{
     for (long long i = 0; i < 10000LL; ++i)
     {
          total += i;
     }
}
 
std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;     //0
void f(int n)
{
     while (lock_flag.test_and_set(std::memory_order_acquire))
     {
          std::cout << "Waiting from thread " << n << std::endl;
     }
     std::cout << "Thread " << n << " starts working." << std::endl;
}
 
void g(int n)
{
     std::cout << "Thread " << n << " is going to start." << std::endl;
     lock_flag.clear();
     std::cout << "Thread " << n << " starts working." << std::endl;
}
 
//将lock封装为锁操作
void Lock(std::atomic_flag* lock)
{
     while (lock->test_and_set());
}
 
void Unlock(std::atomic_flag* lock)
{
     lock->clear();
}
 
int main()
{
     std::thread t1(fun);
     std::thread t2(fun);
     t1.join();
     t2.join();
     std::cout << total << std::endl; //99990000

     //注意点:
     /*
          对于线程而言,原子类型属于“资源型”数据,意味着多个线程通常只能访问单个原子类型的拷贝,
          因此在C++11中,原子类型只能从其模板参数类型中进行构造,
          标准不允许原子类型进行拷贝构造,移动构造,以及使用operator=等操作
          实际上,atomic类模板的拷贝构造,移动构造,operator=等操作默认是被删除的
     */
     std::atomic<int> ai1 = 1; //std::atomic<int> af1{1};
     std::atomic<int> ai2 = ail; // error
     std::atomic<int> ai3{ ai1 }; // error
     /*
          不过从atomic<T>类型的变量来构造起模板参数类型T的变量则是可以的
          这是由于atomic类模板总是定义了从atomic<T>到T的类型转换函数,
          在需要时,编译器会隐式地完成从原子类型到其对应的模板参数类型的转换
     */
     int i1 = ai1;      //等价于 int i1 = ai1.load();
     int i2{ ai1 };
     ai1 = 2;     //等价于 ai1.store(2);
     ai1--;      //等价于 ai1.operator()--
     //具体atomic原子类型方法参考头文件<atomic>
     std::cout << "===================================" << std::endl;

     //特殊的布尔型atomic类型:atomic_flag
     /*
          atomic_flag是无锁的,即线程对其访问不需要加锁,因此也就不需要load,store等成员函数来进行读写; 而通过test_and_set和clear,可以实现自旋锁
     */
     /*
          解释下面代码:声明一个全局的atomic_flag变量lock_flag,初始状态为ATOMIC_FLAG_INIT,即为false状态,在线程t3中不停的通过lock_flag变量的成员test_and_set来设置lock_flag为true,而test_and_set()是原子操作,用于在一个内存空间原子上写入新值并返回旧值,因此test_and_set会返回之前的lock_flag的值。由于main函数中调用了test_and_set,所以f函数中的test_and_set将一直返回lock_flag为true,并不断打印,即自旋等待;当线程t4加入运行的时候,其g函数调用了lock_flag的成员clear,将lock_flag值设为false,从而是线程t3的自旋终止,开始运行后面的代码。
     */
     lock_flag.test_and_set();
     std::thread t3(f, 1);
     std::thread t4(g, 2);
 
     t3.join();
     Sleep(100);
     t4.join();
     return 0;
}

====================打个广告,欢迎关注====================

QQ:412425870
csdn博客:
http://blog.csdn.net/caychen
码云:
https://gitee.com/caychen/
github:
https://github.com/caychen

点击群号或者扫描二维码即可加入QQ群:

328243383(1群)



点击群号或者扫描二维码即可加入QQ群:

180479701(2群)




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值