0%

10.动态内存

10.1 生命周期

目前的我们接触到的对象或者静态static都有着严格的生命周期:

  • 全局:程序启动时自动分配,程序结束时销毁
  • 局部对象:进入其所定义的程序时被创建,离开块时销毁
  • 静态:第一次使用前分配,程序结束时销毁

上述中的变量只使用了静态内存和栈内存。它们会自动创建和销毁。静态内存保存局部static、类static成员以及定义在任何函数之外的变量。栈内存保存定义在函数内的非static对象

除了上述的自动分配外,c++还支持动态分配对象。(其生命周期与它们在哪创建无关,只有显式的被释放时,这些对象才会被销毁)。它们被分配在内存池,称作自由空间或堆。程序用堆来存储动态分配

阅读全文 »

1 condition_variable:同步

上面的互斥锁只是在共享数据处执行保护操作,但是数据的同步,即线程对数据的操作的先后次序并不确定,当我们还想对线程同步时,必须采取一定的同步操作。条件变量是达到这个目的方法。

C++标准库对条件变量有两套实现:

  • std::condition_variablestd::condition_variable_any 。这两个实现都包含在<condition_variable>头文件的声明中。两者都需要与一个互斥量一起才能工作(互斥量是 为了同步)
    • 前者仅限于与std::mutex一起工作,
    • 而后者可以和任何满足最低标准的互斥量一起工作,从而加上了_any的后缀,因此从体积、性能,以及系统资源的使用方面产生额外的开销.
    • 所以 std::condition_variable 一般作为首选的类型,当对灵活性有硬性要求时,我们才会去考虑 std::condition_variable_any
阅读全文 »

1 C++中的锁

1.1 C++中的锁机制

C++中的锁机制以下几种:

  • 互斥锁:包括std::mutex、std::recursive_mutex、std::timed_mutex、std::recursive_timed_mutex等。互斥锁用于保护共享资源,可以保证同一时刻只有一个线程访问共享资源。

  • 读写锁:包括std::shared_mutex、std::shared_timed_mutex等。读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。

  • 条件变量:包括std::condition_variable、std::condition_variable_any等。条件变量允许线程等待某个条件发生变化,只有当条件满足时才能继续执行。

  • 原子操作:包括std::atomic、std::atomic_flag等。原子操作用于保证某个操作的执行不会被其他线程中断,从而避免了数据竞争的发生。

  • 自旋锁:包括std::spin_lock、std::atomic_flag等。自旋锁在等待锁的过程中不断地循环检查锁是否可用,而不是放弃CPU,从而避免了线程上下文切换带来的开销。

  • 信号量:包括std::binary_semaphore、std::counting_semaphore等。信号量用于控制同时访问某个资源的线程数量,可以实现线程的互斥和同步。

1.2 悲观锁和乐观锁

在C++中,锁通常被分为两种类型:悲观锁和乐观锁

  • 其中悲观锁是指在访问共享资源时先获取锁,防止其他线程同时修改该资源,适用于写操作多的场景。C++中的互斥锁就是一种悲观锁。
  • 而乐观锁则是在不加锁的情况下,尝试去读取和修改共享资源,如果遇到冲突,再使用重试等机制解决冲突,适用于读操作多于写操作的场景。
    • 在C++中,可以使用atomic类型来实现乐观锁。atomic类型提供了对基本类型的原子操作,包括读、写、比较交换等。在进行原子操作时,它使用硬件原语实现同步,避免了使用锁所带来的额外开销和死锁的问题。
    • 除了atomic类型,C++11还引入了一些使用乐观锁的算法,如无锁队列和无锁哈希表等。这些算法使用原子操作来实现线程安全,同时充分利用了乐观锁的优势,避免了使用锁所带来的开销。

2 Mutex:互斥

所有线程间共享数据的问题,都是修改数据导致的(竞争条件)。如果所有的共享数据都是只读的,就没问题,因为一个线程所读取的数据不受另一个线程是否正在读取相同的数据而影响

2.1 恶性条件竞争

恶性条件竞争通常发生于多线程对多于一个的数据块的修改时,产生了非预想的执行效果,即竞态条件是多个线程同时访问共享资源,导致结果依赖于线程执行的顺序和时间。

  • 竞态条件(Race Condition)指的是多个线程访问共享变量时,最终的结果取决于多个线程的执行顺序。竞态条件不一定总是错误的,但它们可能导致非预期的结果。

  • 数据竞争(Data Race)指的是多个线程同时访问同一个共享变量,并且至少有一个线程对该变量进行了写操作。数据竞争是一种错误,因为它可能导致未定义的行为。

在多线程编程中,竞态条件和数据竞争是常见的问题。解决这些问题的关键是使用同步机制。

避免恶性条件竞争:

  • 要避免恶性的条件竞争,一种方法是就使用一定的手段,对线程共享的内存区域的数据结构采用某种保护机制,如使用锁
  • 另一种就是选择对该区域的数据结构和不变量的设计进行修改,如保证该区域为原子操作,,修改完的结构必须能完成一系列不可分割的变化,但是这种无锁的方法很难一定保证线程安全
  • 另一种处理条件竞争的方式是,使用事务(transacting)的方式去处理该数据共享区域
阅读全文 »

1 volatile

C/C++ 中的 volatile 关键字和 const 对应,用来修饰变量,通常用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明:

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

  • volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。

  • 应对场景:遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化。这是因为volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,就极有可能暂时使用寄存器中的值,此时这个变量由别的线程更新了的话,将出现不一致的现象

  • 示例:int volatile vInt; 当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。例如:

阅读全文 »

1 信息的存储

大多数的计算机使用8位的块,或者说是字节(byte),作为最小的可寻址内存单位,而不是访问内存中单独的位。机器级程序将内存视为一个非常大的字节数组,我们称为虚拟内存,内存的每个字节都由一个唯一的数字来标识,即称为地址;所有可能的地址空间的集合就是虚拟地址空间

顾名思义,虚拟地址空间只是一个展现给机器级程序的概念性映像。实际的实现(第九章:虚拟内存)是将DRAM、闪存、磁盘存储器、特殊硬件和操作系统软件结合起来,位程序提供一个看上去统一的字节数组。

阅读全文 »

1 学习本书的目的

计算机系统由硬件和系统软件组成。本书是推荐给哪些希望深入了解这些组件如何工作,以及这些组件是如何影响程序正确性和性能,以此来提高自身技能的读者。学完本书,你将知道:

  • 如何避免由计算机表示数字的方式引起的奇怪的数字错误(第二章:信息的表示和处理)
  • 学会一些小窍门来优化自己的C代码,以充分利用现代处理器和存储器系统的设计
  • 你将了解编译器是如何实现过程调用的
  • 如何利用这些知识来避免缓冲区溢出错误带来的安全漏洞
  • 将学会如何识别和避免链接时那些令人讨厌的错误(第七章:链接)
  • 学会如何编写自己的Unix shell、自己的动态存储分配包、自己的web服务器
  • 并发带来的希望和陷阱
阅读全文 »

C++11 中引入 std::ref 用于取某个变量的引用,这个引入是为了解决一些传参问题。

我们知道 C++ 中本来就有引用的存在,为何 C++11 中还要引入一个 std::ref 了?主要是考虑函数式编程(如 std::bind)在使用时,是对参数直接拷贝,而不是引用。下面通过例子说明

阅读全文 »

1 概览

23种设计模式主要可以分为三种类型:

  • 创建型模式:用来创建对象

    • 单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。
  • 结构型模式:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。(关注对象和类的组成关系)

    • 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
  • 行为型模式:关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和协作,进一步明确对象的职责

    • 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
阅读全文 »

1 TCP/IP协议

TCP/IP协议套件是一个分层联网协议,它包括因特网协议(ip)和位于其上层的各个协议层。

1.1 OSI七层模型和TCP/IP模型

各层协议主要有:

  • 应用层协议: FTP(文件传输协议)、HTTP(超文本传输协议)、NFS(网络文件系统)
  • 传输层协议: TCP (传输控制协议)、UDP(用户数据报协议)
  • 网络层:IP(英特网互联协议)ICMP(英特网控制报文协议ping) 、IGMP(英特网组管理协议)
  • 链路层协议:ARP(地址解析协议 通过ip找mac地址)、RARP:(反向地址解析协议 通过mac找ip)
阅读全文 »