C++原子操作(6种原子顺序)

更新时间:2023-06-26 03:43:52 阅读: 评论:0

C++原⼦操作(6种原⼦顺序)
⼀、我们要先搞明⽩什么叫原⼦操作?使⽤这个东西有什么⽬的?
原⼦操作:能够操作最接近机器的指令,这个和硬件相关了,虽然和硬件相关,但我们的C11还是整合了这⼀切,让原⼦操作有了共同的调⽤接⼝
⽬的:使⽤这个的⽬的说实话,就是让你更了解机器已及多线程同步的原理和秘密,当然有⼀些需求较简单的,使⽤原⼦操作可能⽐封装好的更有效率!!⽤了百遍的mutex可能你现在还不知道他们是怎么互斥的~当然内部还是通过了原⼦操作来的!
navigational⼆、讲讲原理
原⼦操作只有2种状态,⼀种是没做,⼀种是做完了,看不到正在做的状态,这个是在任何线程下都满⾜这个要求,当两个线程同时访问⼀块内存的时候,如果有任何⼀个在写,那肯定会产⽣竞争,如果两个同时读,没有问题,那如何⽤原⼦操作来控制不产⽣竞争呢?可以这样来想,当两个线程在访问的时候,⼀定有⼀个先后顺序,谁先访问,谁后访问,这就是修改顺序,我们要在任何线程可以看到这样的顺序!然后就可以通过⼀定的逻辑来处理并发竞争的情况了!
三、标准库操作
例:我们⼀实现⼀个线程读取,⼀个线程写⼊,当然,要先写⼊才能读取,所以这个是顺序问题。
⽅法⼀:condition_variable来操作
雅虎宝贝鱼翻译
结果:每隔1秒打印 ⽅法⼆:使⽤标准原⼦操作
/*
使⽤condition_variable ,读线程wait ,直到写线程调⽤ notify_all,即停⽌等待
*/
#include <thread>
#include <condition_variable>
#include <iostream>
using  namespace  std;
condition_variable g_CV;
mutex g_mtx;
void  read_thread()
{
while  (true )
{
unique_lock<mutex> ul(g_mtx);
g_CV.wait(ul);
cout << g_value << endl;
}apd
}
void  write_thread()
{
while  (true )
{
Sleep(1000);
lock_guard<mutex> lg(g_mtx);
g_value++;
ify_all();
}
}
int  main()
{
thread th(read_thread);
th.detach();
thread th2(write_thread);
th2.detach();
char  a;
while  (cin >> a);
return  0;
}
/*使⽤原⼦操作来控制线程顺序,实现了⼀个类似于互斥锁这么⼀个概念*/
#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
int g_value(0);
atomic<bool> g_data_ready(fal);
void read_thread()
{
while (true)葡萄英语怎么读
{
while (!g_data_ready.load());//⽤于控制进⼊
cout << g_value << endl;
g_data_ready = fal;
}
}
void write_thread()
{
while (true)
{
while (g_data_ready.load());//⽤于控制进⼊
Sleep(1000);
g_value++;
g_data_ready = true;
}
}
int main()
{
thread th(read_thread);
th.detach();
thread th2(write_thread);
th2.detach();
char a;
while (cin >> a);
return0;
}
结果:每隔1秒打印
四、六种原⼦操作内存顺序
这个⽐较的头痛了,对于刚接触这个概念的时候,我也是⼀头雾⽔。。但随着我各种查资料,慢慢就有所理解,知乎的⼀位答主讲的⽐较不错,,再加之深究《C++并发编程实战》第五章的内容。
//这⾥枚举这六种
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_relea,
memory_order_acq_rel,
memory_order_q_cst
} memory_order;
memory_order_q_cst :这个是默认的原⼦顺序,即按代码怎么写的就是怎么个顺序!
memory_order_relaxed:这个是松散顺序,《C++并发编程实战》第5章 123页举的例⼦讲的很清楚,鉴于篇幅,我也简单陈述⼀下,举书本上的例⼦:
#include <atomic>
#include <thread>
#include <asrt.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true,std::memory_order_relaxed);    #1
y.store(true,std::memory_order_relaxed);    #2
busy的用法}
void read_y_then_x()
{
while(!y.load(std::memory_order_relaxed));  #3
if(x.load(std::memory_order_relaxed))      #4
++z;
}
int main()
{
orange flowerx=fal;
广州出国y=fal;
z=0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
asrt(z.load()!=0);                        #5//断⾔发⽣,z是可能等于0的
}
为什么断⾔可能发⽣?意思是z可能为0,x可能为0,这个问题,就是relaxed的锅, 在write_x_then_y线程中,因为#1,#2的store是松散的,在read_y_then_x线程中,也是以松散来读的,x与y没有必然的联系,意思是x.load的时候,可能返回fal,编译器或者硬件可随便更改线程中的顺序,所以说慎⽤使⽤松散顺序!还有就是这种是理想条件下的,⾄少x86Cpu⽬前没有该功能!
ctymemory_order_relea,memory_order_acquire:我把这个放在⼀起,因为这两个是⼀套的,要搭配使⽤,举个例⼦来
#include <atomic>
#include <thread>
#include <asrt.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x()
{
x.store(true,std::memory_order_relea);
}
void write_y()
{
y.store(true,std::memory_order_relea);
}
void read_x_then_y()
{
while(!x.load(std::memory_order_acquire));
if(y.load(std::memory_order_acquire))//y为fal;
++z;
}
void read_y_then_x()
{
while(!y.load(std::memory_order_acquire));
if(x.load(std::memory_order_acquire))//x为fal;
++z;
}
int main()
{
x=fal;
y=fal;
嘿裘德z=0;
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
短裙配什么上衣asrt(z.load()!=0);
}
z这次会触发,意思是z=0,原因4个线程相互独⽴,relea与acquire是⼀种同步的搭配,但他们必须配对,如果不配对,就像relaxed⼀样,返回先前的值。
memory_order_relea,memory_order_consume 这两个也是⼀对的,配对使⽤才能同步,与acquire区别在这⾥

本文发布于:2023-06-26 03:43:52,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/90/157864.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:顺序   操作   线程   并发   可能
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图