程序员自我修养笔记1

Interface的概念:计算机中,每个层次之间的通信协议(这里的接口区别于Java等编程语言的接口)。

内存管理

内存的分段管理:
基本思路是把一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空间。给出一个示例图:

但是分段存在一个效率问题,比如我们的硬盘是100M,此时由10M、80M和30M三个程序,不论怎样分段,都无法完成高效的映射。

内存的分页管理:
分页的基本思路是把内存的地址空间人为的分成固定大小的页,操作程序可以有部分在内存中,有部分在磁盘中。根据程序利用的“二八法则”,可以灵活地调整内存分配。
在这里插入图片描述

线程、进程与并发

进程拥有独立的地址空间,资源对外封闭,是操作系统调度的单位。线程是CPU执行的单位,是轻量级的继承,有自己的寄存器集合和堆栈,但是资源不封闭。

线程或者进程会有不同的状态,基本的状态转化图:

Linux与windows相比,创建进程消耗的资源更少,可以快速创建大量的进程,创建方式有三种,分别是:

  • fork:复制当前进程
  • exec:使用新的可执行映像覆盖当前可执行映像
  • clone:创建子进程并从指定位置开始执行

fork的速度非常快,fork本身不会立刻复制原来任务的内存空间,而是和原来的任务共享写时复制的内存空间。写时复制是指两个任务可以同时自由读取内存,如果任意一个任务对内存空间进行写的操作,那么内存就会复制一份给修改方单独使用。

fork只能产生本任务的镜像,我们可以先fork一个进程,然后调用exec函数来执行一个新的任务,从而达到多进程执行不同任务的目的。

锁、互斥量和信号量的概念:

  • 锁:锁是一个概念,是为了保护某个代码段只能同时被一个线程所访问,这个代码段成为临界区。
  • 信号量:访问信号量的值小于0时,线程进入等待状态;在访问资源完成后,信号量的值加1,如果此时信号量的小于1,则唤醒一个等待的线程。二元信号量是最简单的锁的结构。信号量可以被任何的线程释放!!!
  • 互斥量mutex:资源仅仅允许一个线程访问,但是互斥量只能被获取互斥量的线程释放。

可重入函数:在函数调用结束前,如果有其他的线程调用该函数,函数产生的结果不会发生变化。可重入函数是并发执行的保障。

编译器的过度优化和volatile关键字

首先要明白,线程拥有各自独立的寄存器,线程在读取变量的时候,会先从内存获取数据添加到自己的寄存器中,然后在寄存器中操作完毕后放回内存中。第一个过度优化的情况是,编译器为了提高程序速度,在寄存器操作完后,不把数据立刻放回内存中,而可能过一段时间才放回内存;第二个过度优化是,编译器可能把看似逻辑上不相关的操作指令调换顺序。

第一个操作带来的问题:

x = 0;
Thread1    Thread2
lock();    lock();
x++;       x++;
unlock();  unlock();

虽然加锁了,但是程序执行自增操作后,此时某个线程离开了临界区,为了优化速度不把寄存器的x立刻放回内存,那么另一个程序操作的数据是没有更新的,这样就是造成数据错误。

第二个操作带来的问题:

x = y = 0;
Thread1    Tread2
x = 1;     y = 1;
r1 = y;    r2 = x;

编译器为了优化速度,可能把看似不相关的程序调换下位置,比如x = 1r1 = y的顺序被调换了,那么r1r2就会出现同时为0的情况。

volatile指令可以做两件事情:

  • 阻止编译器为了提高速度把一个变量缓存到寄存器而不写回内存
  • 阻止编译器调整volatile变量的指令顺序

但是,volatile无法阻止CPU动态调度换序,因此还是存在并发的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值