程序员自我修养杂记

计算机
对于系统程序开发者来说,计算机三个部件最为关键:CPU、内存、I/O控制芯片。
高速的北桥芯片:为了协调CPU、内存和高速的图形设备。此时慢速的I/O总线已经无法满足需求。
低速设备的南桥芯片:由于北桥芯片运行速度非常高,于是人们有设计了低速设备的南桥芯片,磁盘、usb、键盘、鼠标等设备都连接在南桥芯片上,由南桥芯片将他们汇总后链接到北桥上。
SMP(对称多处理器)多CPU的计算机;简单的来讲就是每个CPU在系统中所处的地位和发挥的功能是一样的,是相互对称的。使用场景:大型数据库、网络服务器上,他们要求同时处理大量的请求,而这些请求时相互独立的,所以多处理器就可以最大效能的发挥作用。多处理器最多的应用场合时这些商用的服务器和需要处理大量计算的环境。(CPU频率碰到了天花板4GHZ,才出现了SMP).
多核处理器:实际上就是SMP的简化版。这是由于多处理器成本高,所以厂商将多个处理器“合并在一起打包出售”,这些被打包的处理器之间共享比较昂贵的缓存部件,只保留多个核心;并且以一个处理器的外包装进行出售,价格比单核处理器只贵一点。当然他们在缓存共享方面有细微的差别,但是从程序员的角度来看,他们的区别很小,逻辑上看他们是完全相同的。
系统软件:传统意义上一般将用于管理计算机本身的软件称为系统软件,以区别普通的应用程序。系统软件可以分为两块;一块是平台性的,比如,操作系统内核、驱动程序、运行库和数以千记得系统工具;另一块是用于程序开发的,比如,编译器、链接器、汇编器等开发工具和开发库。
计算机系统软件体系结构采用一种层的结构:计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。
接口:每个层次之间都必须要相互通信,则需要一个通信协议,我们一般将其称为接口。接口下面那层是提供者,上层是使用者。除了硬件和应用程序,其他层都是中间层,每个中间层都是对它下面的那层的包装与扩展。正是由于这些中间层的存在,使得应用程序和硬件之间保持相对独立。

在软件体系结构中:位于最高层的是应用程序。从整个层次结构上来看,开发工具与应用程序属于同一层,因为他们都使用同一接口,那就是操作系统应用程序编程接口。应用程序接口的提供者是运行库。
运行库使用操作系统提供的系统调用接口,系统调用接口往往以软中断的方式提供;比如,linux使用0x80号中断作为系统调用接口。
硬件规格: 操作系统内核层对于硬件层来说是硬件接口的使用者,而硬件是接口的定义者,硬件的接口的定义决定了操作系统的内核,具体来讲就是驱动程序如何操作硬件,如何与硬件通讯,这种接口被叫做硬件规格。

操作系统:一个功能是提供抽象的接口,另外一个主要功能就是管理硬件资源。
多道程序的设计:编写一个监控程序,当某个程序暂时无需使用CPU时,监控程序就把另外的正在等待CPU资源的程序启动起来,使得CPU能够充分利用起来,这种被称为多到程序。
分时系统:每个程序运行一段时间后都主动让出CPU给其他的程序,使得一段时间内每个程序都有机会运行一小段时间。
多任务系统:操作系统接管了所有的硬件资源,并且本身运行在一个受硬件保护的级别,每个进程都有自己的独立空间,使得进程之间的地址相互隔离。CPU由操作系统同一分配,每个进程都会根据进程优先级的高低都有机会得到CPU.但是,如果运行超出了一定的时间,操作系统会暂停该进程,将CPU资源分配给其他的等待运行的进程,这种CPU分配方式为抢占式。

驱动程序可以看做事操作系统的一部分,它往往和系统内核一起运行在特权级别,但他与操作系统内核之间有一定的独立性,使得驱动程序有较好的灵活性。操作系统开发者为硬件生产商提供了一系列接口和框架,凡是按照这个接口和框架开发的驱动程序都可以在该操作系统上使用。

进程的总体目标是希望每个进程从逻辑上看都可以独占计算机的资源。操作系统的多任务功能使得CPU能够在多个进程之间共享;从进程的角度看好像是他独占了CPU而不用考虑与其他进程分享CPU的事。操作系统的I/O抽象模型也很好的实现I/O设备的共享和抽象。内存通过虚拟地址空间;分段分页来实现共享。

为什么要虚拟内存:
如果程序直接在物理内存上使用,直接访问物理地址将带来很多问题:

1. 地址空间不隔离:所有程序都访问物理地址,程序所使用的内存空间不相互隔离,恶意的程序可以很容易改写其他程序的内存数据,以达到破坏的目的。有些非恶意、但有臭虫的程序可能不小心修改ill其他程序的数据,就会使其他程序崩溃。而使用虚拟地址空间可保证一个任务的失败不影响其他任务的执行。
2. 内存使用效率低:由于没有有效的内存管理机制,通常需要一个程序执行时,监控程序就将整个程序装载进内存然后执行。内存不够时会发生大量的数据交换,效率低下。
3. 程序运行的地址不稳定:因为程序每次需要装入运行时,我们都需要给他从内存中分配一块足够大的内存空间区域,这个区域位置不确定;这给程序的编写造成一定的麻烦,因为程序在编写时,它访问的数据和指令跳转时的目标地址很多都市固定的,这涉及到重定位问题。

解决问题的思路就是增加中间层,即使用一种间接地址访问方法。我们把程序给出的地址看作是一种虚拟地址,然后通过某种映射,将虚拟地址转换为物理地址。这样,只要我们能够妥善控制这个虚拟地址到物理地址的映射过程,就可以保证任意一个程序所能够访问的物理内存区域跟另一个程序相互不重叠,以达到地址空间隔离的效果。物理地址空间是真真实实存在的;虚拟地址空间是指虚拟的,而且每个进程只能访问自己的地址空间,这样就有效的做到了进程的隔离。

分段:解决了第一个和第三个问题。首先,它做到了地址的隔离,如果程序访问越界,将会被硬件判断为非法访问,拒绝这个地址请求,并将这个请求报告给操作系统或者监控程序。再者,对于每个程序员来说,无论他们被分配到物理地址的那个区域,对于程序来说都是透明的。他们不需要关心物理地址的变化。 但分段没有解决内存使用效率问题;分段对内存区域的映射还是按照程序为单位;如果内存不足,被换入换出到磁盘的都是整个程序,这样势必会造成大量的磁盘访问操作,从而严重影响速度。这种方法换是显得比较粗糙,粒度比较大。
事实上,根据程序的局部性原理,当一个程序在运行时,在某个段内,它只是频繁的用到一小部分数据,也就是说,程序的很多数据其实在一段时间内都是不会被用到的。人们很自然的想到了更小粒度的内存分割和映射的方法,使得程序的局部性原理得到充分的利用,大大提高了内存使用率,这种方法就是分页。
分页:提高了内存的使用率,减少了内存碎片的产生;保护也是页映射的目的之一。简单来说就是每个页可以设置权限属性,只有操作系统有权限修改这些属性。MMU都集成在CPU的内部了,不会以独立的部件存在。

线程基础
线程:有时被称为轻量级的进程(LWP),是程序执行流的最小单位。一个标准的线程是由线程ID\当前指令指针(PC)、寄存器集合和堆栈组成。通常意义上,一个进程由一到多个线程组成,各个线程之间共享程序的内存空间(包括代码段、数据段、堆等)以及一些进程级的资源(打开的文件和信号)。
使用多线程的原因:
1. 某个操作可能会陷入长时间的等待,等待的线程会进入睡眠状态,无法继续执行,多线程执行可以有效的利用等待的时间。典型的例子是等待网络响应,这可能要花费数秒。
2. 某个操作(计算)会消耗大量的时间,如果只有一个线程,程序和用户之间的交互会中断。多线程可以让一个线程负责交互,另一个线程负责计算。
3. 程序本身就要求并发操作。、
4. 多CPU或多核计算机,本身具备同时执行多个线程的能力,因此单个线程程序无法全面的发挥计算机的全部计算能力。
5. 相对于多进程应用,多线程在数据共享方面效率要高得多。

线程的访问权限
线程的访问非常自由,它可以访问进程内存空间内的所有数据,甚至包括其他线程的堆栈(如果他知道其他线程的堆栈地址,这是很少见的情况),但实际运用中线程也拥有自己的私有存储空间:
1. 栈:尽管并非完全无法被其他线程访问,但一般情况下仍然可以认为是私有数据。
2. 线程局部存储,是某些操作系统为线程单独提供的私有空间,但通常只具有很有限的容量。
3. 寄存器:寄存器是执行流的基本数据,因此为线程私有。

从C程序员的角度看,数据在线程之间是否私有:
私有:局部变量、函数参数、TLS线程局部存储数据
线程之间共享进程所有:全局变量、堆上的数据、函数里的静态变量、程序代码,任何程序都有权读取并执行任何代码、打开的文件。

线程调度:一个不断在处理器上切换不同线程的的行为。线程通常至少拥有三种状态:运行、就绪、等待。
IO密集型线程:频繁等待的线程;CPU密集型线程:很少等待的线程;IO密集型的线程总比cpu密集型的线程容易得到优先级的提升。

对于linux来说,线程并不是一个通用的概念;linux对多线程支持颇为贫乏;事实上,在linux内核中并不存在真正意义上的线程的概念。Linux将所有可执行的实体称为任务(TASK),无论是进程换是线程。每一个任务概念上都类似于一个单进程的线程,具有内存空间、执行实体、文件资源。不过,linux下不同任务之间可以选择共享内存空间,因而在实际意义上,共享同一个内存空间的多个任务构成了一个进程,这些任务也就成为了这个进程里的线程。在linux下,用以下方法可以创建一个新的任务。

系统调用
作用
效果
fork
复制当前进程
新的任务启动并和本任务一起从fork返回,本任务返回的是新任务的pid,新任务返回0。Fork速度非常快,因为采用了写时复制。Fork只能产生本任务的镜像。
exec
使用新的可执行映像覆盖当前可执行映像
Fork+exec启动别的新任务。
Clone
创建子进程并从指定位置开始执行
产生新的线程使用clone。从指定的位置开始执行,并且(可选)共享当前的内存空间和文件等。如此就可以在实际效果上产生一个线程。

线程安全
同步:为了避免多个线程同时读写同一个数据而产生不可预料的结果,我们需要将各个线程对同一个数据的访问同步。所谓的同步,既是指在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。如此,对数据的访问被原子化了。
同步的方式:
1. 锁、
2. 二元信号量、(多元)信号量(对于允许多个线程并发访问的资源,它是一个很好的选择;一个初始值为n的信号量允许N个线程并发访问。)
3. 互斥量:和二元信号量很类似,资源进同时只能被一个线程访问。不同的是,信号量在整个系统可以被任意线程获取并释放。而互斥量则要求那个线程获取了互斥量,那个线程就要负责释放这个锁。
4. 临界区:是比互斥量更加严格的同步手段。把临界区的锁获取称为进入临界区,释放称为离开临界区。临界区和互斥量与信号量的区别在于,互斥量和信号量在系统的任何进程里都是可见的,也就是说,一个进程创建了一个互斥量或者信号量,另一个进程试图获取该锁是合法的。然而,临界区的作用范围仅限于本进程,其他进程无法获取该锁。除此之外,临界区胡互斥量具有相同的性质。
5. 读写锁:适用于读频繁写少的情况。对于一段数据,多个线程同时读取总是没有问题的,写时必须上锁。
6. 条件变量:作用类似一个栅栏。线程有两种操作,等待与唤醒。使用条件变量可以让许多线程一起等待某个事件的发生,当时间发生时,条件变量被唤醒,所有的线程可以一起恢复执行。

可重入与线程安全
一个函数要被重入只有两种情况:一是多个线程同时执行这个函数;二是函数自身调用自身。一个函数被重入表示这个函数没有被执行完成,由于外部因素或者内部调用,又一次进入函数执行。一个函数可重入,表明函数重入后不会产生任何不良的后果。一个函数要成为可重入的,必须具有如下几个特点:
1. 不使用任何(局部)静态或全局的非const变量。
2. 不返回任何(局部)静态或者全局的非const变量的指针。
3. 仅依赖于调用方提供的参数。
4. 不依赖任何单个资源的锁。
5. 不调用任何可重入的函数。
可重入是并发的强力保障,一个可重入的函数可以在多线程环境下放心使用。

过度优化;
Volatile关键字:一是阻止编译器为了提高速度将一个变量缓存到寄存器中而不写回;二是阻止编译器调整volatile变量的指令顺序。
Barrier:因为即使volatile可以阻止编译器调整顺序,也无法阻止CPU动态调度换序。现在并不存在可移植的阻止换序的方法。通常情况下是通过调用CPU提供的一条指令,这条指令被称为barrier。它可以阻止cpu将该指令之前的指令交换到它之后,反之亦然。Barrier指令的作用类似于一个拦水坝,阻止换序穿透这个大坝。

三种线程模型
Windows和linux,都是在内核里提供线程的支持。内核线程,这里的内核线程和linux内核里的kernel_thread并不是一回事,它和我们之前讨论的一样,由多个处理器或调度器来实现并发。然而用户实际使用的的线程不是内核线程,而是存在于用户态的用户线程。用户线程并不一定在操作系统内核内对应着同样数量的内核线程。
用户态多线程库的实现
一对一模型:用户线程具有和内核线程一致的优点,线程之间的并发,是真正的并发。一个线程阻塞,其他线程不会受到影响。一对一模型可以让多线程程序在多处理器的系统上有跟好的体现。一般直接使用API或系统调用创建的线程均为一对一的线程。 缺点:一是由于许多操作系统限制了内核线程的数量,因此一对一线程会让用户的线程数量受到限制。二是许多操作系统内核线程调度时,上下文切换开销大,导致用户线程的执行效率下降。
多对一模型:线程间的切换由用户态的代码来进行,线程切换的速度要快许多,但是一个用户线程阻塞,那么所有线程都将无法执行,因此此时内核里的线程也随之阻塞了。多对一模型的好处就是高效的上下文切换和几乎无限制的线程数量。
多对多模型:一个用户线程阻塞并不会使得所有用户线程阻塞,因为此时还有别的线程可以被调度来执行。另外,多对多模型对用户线程的数量没有什么限制,在多处理器上,线程也能得到一定性能的提升。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值