当前位置: 首页 > news >正文

网站建设易网宣seo北京公司

网站建设易网宣,seo北京公司,wordpress 按时间显示文章,摄影师个人网站制作文章目录why atomic?sequentially consistent atomicRelaxed memory modelswhy atomic? 当我们有一片内存空间S,线程A正在往S里写数据,这个时候线程B突然往S中做了操作,导致线程A的操作结果变得不可预知(对线程A来说),这种情况换句话说叫做data race,我们一般的操作时上锁,在…

文章目录

  • why atomic?
  • sequentially consistent atomic
  • Relaxed memory models

why atomic?

当我们有一片内存空间S,线程A正在往S里写数据,这个时候线程B突然往S中做了++操作,导致线程A的操作结果变得不可预知(对线程A来说),这种情况换句话说叫做data race,我们一般的操作时上锁,在c++中有多种类型的锁比如std::mutex,std::shared_mutex(c++ 17),

std::mutex的性能要比std::shared_mutex低,因为std::shared_mutex上锁后其他线程可以照样可以访问被lock住的空间(只可以读原数据),而一旦线程对一块内存区域上std::mutex锁后,其他的线程无论读还是写都不会成功

mutext使用如下

#include <iostream>
#include <mutex>
#include <thread>class A{public:A() = default;~A() = default;void add_element(int num);static int element;
private:std::mutex m;};int  A::element = 0;void A::add_element(int num){m.lock();std::cout << "thread " << std::this_thread::get_id() << " add " << num << std::endl;element = element + num;m.unlock();
}int main(){A a;std::thread worker[5];for(int i  = 0; i < 5; i++){worker[i] = std::thread(&A::add_element, std::addressof(a), i);worker[i].join();}}

注意!
如果std::thread()添加的函数对象在class外部,且调用std::thread()的函数也不属于任何一个class,那么就直接调用,std::thread()第二个参数佳被调用函数的第一个参数
如果std::thread()添加的函数对象在class内部(class 内部非静态函数如我们上面的例子所示),他要除了要将函数的全部名称(包含class名字)写上去,还要指定我们这个class对象的位子,这样才能寻址到指定的函数,std::thread()第三个就是该被注册函数的第一个参数
如果std::thread()位于某个class内部,且注册的函数也位于这个class内部我们和上面一样需要指定这个class的起使位子(thisstd::thread()的第二个参数中)

shared_mutext使用如下

#include <iostream>
#include <shared_mutex>
#include <thread>class A{public:A() = default;~A() = default;void add_element(int num);void get_element();static int element;
private:std::shared_mutex m;};int  A::element = 0;void A::add_element(int num){//for set lockm.lock();element = element + num;m.unlock();
}void A::get_element(){//for read lockm.lock_shared();std::cout << "thread " << std::this_thread::get_id() << " get element "<< element  << std::endl;m.unlock_shared();
}int main(){A a;std::thread worker[5];for(int i  = 0; i < 5; i++){worker[i] = std::thread(&A::add_element, std::addressof(a), i);worker[i].join();worker[i] = std::thread(&A::get_element, std::addressof(a));worker[i].join();}}

现在回归正题,为什么我们要使用atomic而不是锁?首先我们在用atomic的时候发现系统明显的慢,并且我们的锁颗粒已经小到极致,那么为了再进一步的提升性能我们只能使用atomic
首先锁的一些操作都是操作系统提供,比如win,linux,但是atomic是我们处理器提供的,锁机制其实是将被lock住的线程挂起,空出cpu资源给其他的线程,但是这有明显的inter pross的线程上下文切换(被锁住的线程在不断地尝试直到成功强到锁(也叫做busy wait))我们使用锁的时候还要考虑死锁等情况发生(当然c++中有lock_guardclass将一个锁包住当lock_guardclass对象被销毁自动的unlock)

而我们的atomic就简单的多,只需要将容易发生race的那个变量置为atomic即可

#include <iostream>
#include <shared_mutex>
#include <thread>
#include <chrono>
#include <atomic>class A{public:A() = default;~A() = default;void add_element(int num);void get_element();static std::atomic<int> element;
private://std::shared_mutex m;};std::atomic<int> A::element{0};void A::add_element(int num){//for set lock//m.lock();element = element + num;//m.unlock();
}void A::get_element(){//for read lock//m.lock_shared();std::cout << "thread " << std::this_thread::get_id() << " get element "<< element  << std::endl;//m.unlock_shared();
}int main(){A a;std::vector<std::thread> worker;for(int i  = 0; i < 5; i++){worker.push_back(std::thread(&A::add_element, std::addressof(a), i));}for(int i = 5; i < 10; i++){worker.push_back(std::thread(&A::get_element, std::addressof(a)));}for(auto& currth : worker){currth.join();}return 0;    
}

atomic 在C++标准中并没有说明他是lock-free的,有的平台他是lock-free,有的平台他是用mutex实现,所以C++提供了一个method去验证你的这个平台上atomic 是否是lock-free

bool std::atomic::is_lock_free()

Lock-free usually applies to data structures shared between multiple threads, where the synchronisation mechanism is not mutual exclusion; the intention is that all threads should keep making some kind of progress instead of sleeping on a mutex.

sequentially consistent atomic

首先如果使用了atomic<T>,那么C++是可以保证sequentially consistent atomic特性的
什么是sequentially consistent atomic?他所保证的特性如下

  1. 所有线程的operation中load和store操作是对所有其他线程可见
  2. 必须要遵从(源码)顺序执行

比如我们有2个thread,A和B,其中A执行如下2个操作

thread A
x.store(1);
reg1 = y.load();

线程B执行以下2个操作

thread B
y.store(2);
reg2 = x.load();

假设上述的2个线程的操作遵循sequentially consistent atomic,那么他们的load和store指令是相互可见的(满足条件1),并且每个线程执行atomic operate的顺序严格按照上述伪代码(满足条件2,对于线程A x.store在前y.load在后,对于线程B y.store在前,x.load在这些顺序不能变),那么他们的执行顺序有6种可能

A:x.store(1)--->B:y.store(2)--->A:reg1=y.load()--->B:reg2=x.load()
A:x.store(1)--->B:y.store(2) -->B:reg2=x.load() -->A:reg1=y.load()
A:x.store(1)--->A:reg1=y.load()-->B:y.store(2)-->B:reg2=x.load()
B:y.store(2)--->A:x.store(1)-->A:reg1=y.load()--->B:reg2=x.load()
B:y.store(2)--->A:x.store(1)-->B:reg2=x.load()-->A:reg1=y.load()
B:y.store(2)--->B:reg2=x.load()--->A:x.store(1)-->A:reg1=y.load()

再比如我们2个线程1和2执行下面的指令

线程1指令

x.store(2)
x.load()

线程2指令

x.store(3)

因为load指令是对所有其他线程可见,所以线程1可以看到自己的load指令也可以看到线程2的load指令(限制1),那么执行顺序有3种如下(假设x初始化为1)

1:x.store(2)--->2:x.store(3)--->1:x.load()  结果X=5
2:x.store(3)--->1:x.store(2)--->1:x.load()  结果X=5
1:x.store(2)--->1:x.load()--->2:x.store(3)  结果X=2
2:x.store(3)--->1:x.load()--->1:x.store(2)  结果X=3

上述的顺序永远不会出现,因为1:x.load()不能出现在1:x.store(2)之前,否则违反规则2(代码中规定了执行顺序)

此时你也许会问这有啥用,要知道c++原子操作只会在操作atomic< T > A 的时候是原子的,如下代码

#include <iostream>
#include <thread>
#include <atomic>class A{public:A() = default;~A() = default;void for_thread_1();void for_thread_2();void for_thread_3();static std::atomic<int> element;
private:};std::atomic<int> A::element{0};void A::for_thread_1(){element = element + 2;std::cout << "for thread 1 element is " <<  element << std::endl;
}void A::for_thread_2(){element = element + 3;//std::cout << "for thread 2 element is " << element << std::endl;
}int main(){A a;std::thread worker[3];worker[0] = std::thread(&A::for_thread_1, std::addressof(a));worker[1] = std::thread(&A::for_thread_2, std::addressof(a));worker[0].join();worker[1].join();

如果说我们想要线程1强制在线程2之后执行(结果为5),也就是下面这个顺序

2:x.store(3)--->1:x.store(2)--->1:x.load()  结果X=5

可以这样写

#include <iostream>
#include <thread>
#include <atomic>class A{public:A() = default;~A() = default;void for_thread_1();void for_thread_2();void for_thread_3();static std::atomic<int> element;
private:};std::atomic<int> A::element{0};void A::for_thread_1(){while(element == 0) continue;element = element + 2;std::cout << "for thread 1 element is " <<  element << std::endl;
}void A::for_thread_2(){element = element + 3;//std::cout << "for thread 2 element is " << element << std::endl;
}int main(){A a;std::thread worker[3];worker[0] = std::thread(&A::for_thread_1, std::addressof(a));worker[1] = std::thread(&A::for_thread_2, std::addressof(a));worker[0].join();worker[1].join();return 0;
}

注意c++原子操作一定是在对原子对象操作一瞬间是原子的,比如上述例子中线程1和线程2中每一个对原子对象element操作的句子

也许你还会疑问,以为线程1对element操作的2个语句是一个原子操作,其实这是2个原子操作分别是store和load,我们c++ atomic如果不做特殊的设置默认Sequential consistency
Sequential consistency也是分布式领域大牛2013年图灵奖获得者,强分布式一致性协议paxos的发明者 Leslie Lamport发明的

Relaxed memory models

TODO

http://www.dt0577.cn/news/12585.html

相关文章:

  • 全国城市雕塑建设指导委员会网站头条站长平台
  • 绿色门业宽屏网站模板 破解宁波网站建设推广公司价格
  • 找做企业网站百度认证考试
  • 秦皇岛手机网站制作关键词排名怎样
  • 网站代运营要多少费用郑州seo软件
  • 嘉兴做微网站seo网络推广方法
  • 一家专业做家谱的网站线下引流推广方法
  • 漳州做网站多少钱网站排名点击工具
  • 厅门户网站建设国内营销推广渠道
  • 网站建设成本分析1688精品货源网站入口
  • 怎么做网址导航网站栾城seo整站排名
  • 响应式网站用什么工具做网站如何做seo推广
  • 那个网站可教做课件好灰色项目推广渠道
  • 做网站比较好的企业外贸网站平台哪个好
  • 网站设计与网页制作项目教程百度网盘在线登录
  • 做阿里妈妈没有自己网站怎么推广啊青岛seo用户体验
  • 网站建设售价多少钱鄂尔多斯seo
  • 自己做网站用买域名吗营销型网站定制
  • rp网站做多大百度热搜榜今日头条排名
  • 网站 建设ppt模板网站的优化和推广方案
  • 网站鼠标的各种效果怎么做的seo网络优化平台
  • 中山做营销型网站公司b站推广入口2022
  • 如何做优品快报下的子网站百度网盘下载速度慢破解方法
  • 做网站pageseo网站推广优化
  • 罗湖网站设计费用游戏推广员判几年
  • 360收录seo百度排名优化
  • 福田网站建设标准数据代运营公司排名
  • php企业网站源代码百度网盘搜索引擎入口官网
  • 做网站每年运营要花掉多少钱深圳百度推广竞价托管
  • 杭州网站建设_数据库开发网站_大数据网站开发磁力搜索器kitty