C++原子操作总结

关于乱序 c++程序中,没有依赖关系的语句的执行顺序是无法预测的。 乱序的原因 1. 编译器优化。编译器优化假设程序是单线程环境时,如果编译器出于某种原因会对程序执行顺序并且不会改变其结果,此时是可以乱序执行的。编译器一般不会将函数之后的指令移到函数前面,因为编译器一般不知道函数体内是否含有memory barrier 2. 处理器优化。处理器允许指令乱序,这样避免指令等待资源而暂时hang住,处于闲置状态。eg. cache miss。如果当前指令cache miss,下一条命中,则可能会乱序执行。 3. 存储系统。在每个cpu核中都存在一个store buffer(可以理解成一些特殊寄存器)。在一些写指令执行的时候,写的数据先存在各自的store buffer中,只有自己感知得到,这之后会以先进先出的方式往l2 cache等逐级向下到内存中。而存往store buffer时,cpu就已经认为这条指令执行结束了,因此可能产生乱序。 直面乱序 1. 乱序执行不可避免 2. 如果读写指令涉及的不是共享变量,则不会有坏影响 3. 否则,应该用锁或者原子变…

关于右值

右值 右值定义 右值与左值其实并没有详细官方的定义,官方的其实是一个类似映射表(这个是左值,这个是右值)。但通常来说,下面这个图能覆盖大多数情况。 纯右值(pure right value) 对于大多数临时变量皆为右值。这里的临时变量是指,不能被程序员读写,不存在于内存,其可能只会在寄存器中存在数秒,或者直接被优化掉的变量。 * literal (不含string literal): 42 true nullptr * 返回值不是引用类型的函数 * this指针 * lambda xvalue(expiring lvalue) 即原本为左值,但是程序员确定已经不会再对其读写,可以使用std::move强制让它变为右值。 因此,xvalue必定在一个变量的读写生命周期末尾。 左值 与右值相对,有内存,可以被程序员读写的为左值 * string literal: "2132" * 普通变量: string s * 通过指针访问对象或者对象的数据成员 * 返回是lvalue的函数 * 通过名字访问lvalue对象的数据成…

cnn从入门到入土

cnn全称卷积神经网络(Convolutional Neural Networks),常用于图像分类,语音,机器翻译等。其中最为常见的还是图像分类。 LeNet 总结 各层主要作用 * 卷积层:提取特征 * 池化层:降低计算量 * 全连接:联系各个区域,在分类中结合softmax起到分类器的作用 AlexNet 2012 主要工作与改进点 * 引入ReLU激活函数: ReLU的全称是修正线性单元(Rectified Linear Unit), 其函数表达式为 max(0, x) * 多GPU训练: 加快训练速度 * 引入局部响应归一化(LRN): 实际证明没什么用,在此不对其做解释 * 使用重叠池化:一种池化类型,普通池化是 stride == kernel size,而重叠池化 stride < kernel size * 使用数据增强:一个trick,在数据过少的时候,通过翻转,…

模板线程安全单例C++版本与pthread_once

工作以后单例确实经常用到,复习的时候再次翻开偶然翻到这个 代码来自陈硕的《Linux多线程服务器编程》, 其核心就是用了pthread_once template class Singleton: boost::noncopyable { public: static T& instance() { pthread_once(&ponce_, &Singleton::init); return *value_; } private: Singleton(); ~Singleton(); static void init() { value_ = new T(); } private: static pthread_once_t ponce_; static T* value_; } template pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT;

Python Logging源码解析

前言 python的logging是python内置打印模块,近期因为需要解决框架里的日志耗时长的问题,所以拜读了一下源码,其基础功能的实现源码并不长,截至今日11.15日,python3.8的logging/init.py 大概有4000+行,再算上一些内置方便的handler与config的话,大概会有6000行,总体来说并不是很多。 basicConfig basicConfig是快速且简单配置 root logger 的函数,在一个进程中,默认情况下,这个函数它只会生效一次。因为它有如下判断 if len(root.handlers) == 0: pass 后来这个只生效一次为人所诟病,就又加了一个force参数,能够对其强制更新。 下面说明一下所有参数 参数名称 参数描述 force 强制更新 filename 日志输出到文件的文件名 format 日志输出的格式 datefat 日志附带日期时间的格式 style 格式占位符,默认为 "%" 和 “{}” level…

RapidJSON源码剖析

前言 RapidJSON是腾讯开发的一个开源json解析代码库,因为在公司里经常用到,并且总是会踩坑,因此我这里也开个坑用来记录我对RapidJSON的学习与理解。 学习一个json库,我们关注的无非有以下几点: 1. json如何存储 2. json如何解析与反解析 而选择使用一个json库,我们关注的则是以下几点: 1. 安全性 2. 运行效率 3. 易用性 下面我会按照以上几点一一展开 json存储 关于其存储结构,就我而言第一个想法肯定是直接先构造一个支持增删改查的树,再将这个树运用在json存储中。但其实相当意外的,因为json使用时候的特殊性,其存储结构只要线性(伪)即可。 // AddMember GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString());…

康健计划——内联汇编

内联汇编只能使用AT&T汇编,以前先学的是Intel汇编,更熟悉的也是这个,AT&T汇编也是忘的差不多了。。 Intel汇编与AT&T汇编的区别 区别 intel AT&T 寄存器 寄存器前无前缀 寄存器前有前缀 % 操作数顺序 目的操作数在左,源操作数在右 目的操作数在右,源操作数在左 操作数指定大小 操作数前加修饰符,byte表示8位,word表示16位,dword表示32位 在指令后加字母表示,b表示8位,w表示16位,l表示32位 立即数 无前缀,直接用数字表示 有前缀$ 远跳转 jmp far segment:offset ljmp %segment: %offset 远调用 call far segment:offset lcall %segment: %offset 远返回…