#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.youkuaiyun.com/caychen |
码云: | https://gitee.com/caychen/ |
github: | https://github.com/caychen |
点击群号或者扫描二维码即可加入QQ群: | ![]() |
![]() |