首页 > 编程知识 正文

体育教师面试技能展示,acm模式和核心代码模式

时间:2023-05-05 05:42:44 阅读:57344 作者:2922

概要什么是自动的? Q2 alignas关键字Q3 C的内存模型relaxed ordering,release-acquire ordering,sequentiallyconsistentorderingq4atomic _ compare _ excquire

概要

本章主要介绍有关无锁编程的技能。 在生产环境中,锁定是解决线程之间资源共享问题的最常见方法。 这在前一章中也阐述了很多关于同时编程的问题。 关于无锁的情况,也写了无锁队列的实现,但今天的这篇文章主要介绍了无锁编程所需的基础知识,包括atomics、内存模型和内存排序。

什么是自动的? std:atomicT x; 上述代码使用标准库的atomic类型声明了t型原子变量x。 在计算机指令执行过程中,一个变量的变化包括加载(load )、更新(store )、加载(load )三个步骤,原子变量的变化意味着这三个步骤的中间状态在其他线程中不可见,通常通过变量指令的无序排序进行预定

Q2 alignas关键字CPU(32位)可以在一个时钟周期内读取四个连续的存储单元(4字节)。 使用字节对齐可以提高系统性能。 例如,如果将一个int(4字节)放置在奇数内存位置,则完成读取需要2个时钟,但在数据以4字节对齐后,可以一次读取

以下是alignas的使用方法

alignas(32 )长龙a=0; # define xx 1结构nas (xx ) MyStruct {}; templatesize _ tyy=1结构(YY ) MyStruct {}; 静态一致不确定ZZ=1; 结构性(ZZ )矩阵{ }; //char将alignas(int ) char c用int对齐; alignas只能改变较大的值,不能改变较小的值。 如果需要更改较小的值,则暂时不支持# pragma包或_ pragma (微软)。

_pragma(pack(1) ) struct MyStruct {char a; int b; 短丙; 龙龙d; char e; (; _pragma(pack ) )关于Q3 C内存模型relaxed ordering、release-acquire ordering、sequentiallyconsistentorderingc内存模型, 有三种类型的排序:关系排序、加速排序和顺序一致排序,C 11提供六种类型的操作(memooring ) 内存_ order _ acquire,内存_ order _ reelase,内存_ order _ ACQ _ rel,内存

使用relaxed ordering(松弛顺序)、memory_order_relaxed标记原子变量的load和store操作,不强制同时环境中的内存访问顺序,仅保证当前操作的原子性。

在thread1 thread2中定义全局原子变量以访问std:atomicint x=0; std:atomicint y=0; 真红1号

R1=y.load (内存_ order _ relaxed ); //ax.store(R1,memory_order_relaxed; //b萨德- 2

R2=x.load (内存_ order _ relaxed ); //cy.store(1,memory_order_relaxed; //D以上如果cpu执行指令的顺序不正确,则d -’a -’B-’c的顺序,即r1==r2==1。

如果要求某个操作值为原子操作且不需要其他同步保障,则可使用Relaxed ordering模型创建例如计数器的数值

acquire-release ordering(获取-释放顺序)、release和acquire操作在希望同步语义的线程之间成对出现。 例如,原子变量在a线程中用memory_order_release标记其store操作,在b线程中避免标记为memory_oory的cpu指令的顺序混乱,保证了store和load之间的读写顺序。 其他线程的读写顺序不受影响,为什么要混乱呢?

#包含thread #

include <atomic>#include <cassert>#include <string>std::atomic<bool> ready{false};int data = 0;void producer() {data = 100;//Aready.store(true, std::memory_order_release);//B}void consumer() {while(!ready.load(std::memory_order_acquire));assert(data == 100);}int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();return 0;}

A指令始终在B指令之前执行,而D指令一定在C指令之后执行,如果已经退出了while,所以data == 100,那么assert不会捕获

sequentially consistent ordering(顺序一致次序),使用memory_order_seq_cst标记后的原子变量,线程间指令重排的限制与在顺序性代码中进行指令重排的限制时一致的。

Q4 atomic_compare_exchange_weak 与 atomic_compare_exchange_strong的区别

首先,这两个函数是c++11提供的CAS(compare & set)操作
原理是,比较当前值是否符合预期值,如果符合就将当前值变更为最新值,并返回true,如果不符合就将当前值更新为预期值,并返回false。伪代码如下:

if (*obj == *expected) {*obj = desired;return true;} else {*expected = *obj;return false;}

_weak函数在于当前值与预期值一致时,存储也可能失败,而变量的值不会改变,并且返回的是false。这被称为伪失败(spurious failure),而_strong不允许伪失败,那么它需要cpu保证这个操作指令时原子性的,在生产中,我们通常使用while(*_weak) 方式解决伪失败的同时提升处理能力。

Q5 实现一个单生产者单消费者的队列

在并发编程章节,我们采用了锁实现队列,接下来,我们采用原子变量来实现单生产者单消费者队列,避免使用锁时的性能损耗。

#include <assert.h>#include <vector>#include <atomic>template <typename T>class SPSCQueue {private: //采用64位内存对齐方式 alignas(64) std::atomic<int> _readPos;//缓冲区读位置 alignas(64) std::atomic<int> _writePos;//缓冲区写位置 char _padding[64 - sizeof(_writePos)]; //采用数组来存放队列数据 std::vector<T> _buffer;private: //内敛函数的作用在于编译时编译器在内联函数调用的位置嵌入函数体的内容,减少函数调用 //该函数返回消息存入队列缓冲数组的位置 inline int increment(int pos) const { return (pos + 1) % int(_buffer.size()); }public: SPSCQueue(int capacity) : _buffer(capacity + 1), _readPos(0), _writePos(0) { assert(capacity > 0) //capacity是个有符号值,存在溢出情况 assert(capacity + 1 > 0) } bool push_back(const T &item) { //读取 readPos值,保证其他线程在load之后的读写操作不会发生在load之前 const int r = _readPos.load(std::memory_order_acquire); //读取 writePos的值, relaxed保证的是当前线程的writePos值操作的顺序一致性 const int w = _writePos.load(std::memory_order_relaxed); //获取写入位置 const int next_w = increment(w); //写入位置等于读取位置,说明队列已经满了 if (r == next_w) return false; _buffer[w] = item; //保证其他线程在store之前对writePos值的的读写操作不会发生在store之后 _writePos.store(next_w, std::memory_order_release); return true; } bool pop_front(T &item) { //当前线程顺序 int r = _readPos.load(std::memory_order_relaxed); //保证其他线程在load之后的读写操作不会发生在load之前 int w = _writePos.load(std::memory_order_acquired); //队列为空 if (r == w) return false; item = _buffer[r]; _readPos.store(increment(r), std::memory_order_release); return true; }};

生产可用多生产者多消费者的无锁队列

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。