zoukankan      html  css  js  c++  java
  • 总结(一)

    计算机软件体系结构

    每个层次之间的通信的协议叫做接口(Interface)
    开发工具和应用程序在同一层,称之为操作系统应用程序接口(API: Application Programming Interface)。API由运行库来提供,什么样的运行库提供什么样的API。Linux下的glibc提供POSIX的API, Windows提供Windows的API。
    运行库使用操作系统提供的系统调用接口。系统调用常常使用软件中断来实现。Linux常常使用0x80号中断。
    操作系统的硬件接口的使用者,操作系统与硬件进行通信的协议称之为硬件规格

    操作系统

    操作系统的官方解释:操作系统 是一组控制和管理计算机系统中所有资源的程序的集合。
    操作系统的功能:
    处理机(CPU)管理
    单道程序、 多道程序调度
    因为CPU处理速度与I/O速度的极大差距,所以产生了多种CPU调度方式,比如分时系统,多任务系统。
    存储管理
    设备管理
    文件管理
    网络管理

    内存问题

    程序简单装入内存: 分配连续的程序需要的全部的物理内存。
    例如: PA 需要内存10M, PB需要内存100M, PC需要20M
    将前10M分配给A, 10~110M分配给B,这样可以同时运行。
    存在问题:

    • 地址空间不隔离
    • 内存使用效率低
    • 程序运行地址不确定
      解决办法:
      分段: 设置虚拟地址机制,将程序的段通过映射函数映射到物理内存中
    • 分段优点: 分段解决了地址空间不隔离,和程序运行地址重定位的问题,他通过映射使得物理地址对于程序来说的透明的
    • 分段存在问题:但是并没有解决内存使用效率低的问题,因为大块内存的出现会使得出现类似内存碎片得东西。
      分页:使用更小得粒度来进行内存分割和映射。
      一般来说,4KB作为页大小。

    线程和进程

    线程定义

    线程, 轻量级进程, 是程序执行流的最小单元。由线程ID,当前指令指针、寄存器集合和堆栈组成。
    进程和线程之间的关系
    一个进程由一个或者多个线程组成,各个线程之间共享进程级资源(打开的文件或者信号)程序的内存空间(代码段、数据段、堆)
    为什么使用多线程:

    • 单线程存在阻塞等待,利用多线程来避免,利用等待时间进行其他操作
    • 逻辑本身要求多线程,多段通信下载
    • 多核计算机成为单线程程序的效率上限
    • 数据共享方面的优势

    线程的访问权限

    线程调度

    线程调度方式: 优先级调度、轮转法
    优先级调度中的几个概念:
    频繁等待的线程称为IO密集型线程
    很少等待的线程称为CPU密集型线程
    一般来说,IO密集型的线程的优先级较之CPU密集型的线程的优先级要高。
    线程优先级变更的方式:

    • 用户使用函数来进行指定setThreadPriority
    • 根据进入等待状态的频繁程度来进行优先级的提升和降低
    • 长时间得不到执行而提升

    可抢占线程和不可抢占线程

    所谓抢占就是在某个线程在时间片没有用完的前提下,强制从执行状态进入就绪状态。
    不可抢占线程中也有线程主动放弃执行的情况:

    • 主动放弃时间片
    • 试图等待某事件发生的时候

    Linux的多线程

    不同于Windows系统, Linux系统对于多线程的支持并不是那么完善。
    Linux对于每一个执行实体都称之为任务,这是一个单线程的进程,具有内存空间,执行实体。
    具有着共享同一个内存空间的多任务构成了一个进程,这些任务也就成了进程的线程。
    Linux创建线程的方式:
    fork()函数产生一个与当前进程一样的新进程,产生的新进程与主进程之间共享着写时复制的内存空间。
    exec()系列函数是使用一个新的可执行文件映像。
    利用fork产生新进程,然后再新进程中使用exec来产生新任务。

    还有一个函数是clone(),产生新任务,并从指定位置执行,可以继承父进程的某些可选资源。

    线程安全

    多进程中对于非原子性操作,出现操作竞争,会出现重复写入,延迟读的情况。
    原子性操作: 对于CPU来说是单指令操作。
    提高线程安全性的方法:

    • 使用操作系统提供的原子性的操作
    • 使用同步和锁机制
      同步和锁
      同步(synchronization): 在当前进程没有完成数据访问之前,其他线程不能够对该数据进行访问。
      锁(Lock): 在访问资源之前首先试图获得锁,在访问结束后释放锁。如果在访问之前获得锁失败,线程会等待,直到锁重新可用。
      常见的锁:
      二元信号量: 只有两种状态, 占用和非占用
      多元信号量: n元信号量,如果获得该锁后,信号量减一, 释放锁后,信号量加一,当信号量为负数时就进入等待状态。
      互斥量(mutex) 与二元信号量很像。但是不同的是,信号量可以有其他线程获取并释放。但是互斥量要求哪个线程获得的互斥量,哪个线程就需要释放, 其他线程无法释放。
      临界区 比互斥量更加严格的手段。与互斥量的区别是:临界区的范围仅仅限制与本进程,其他进程无法获得该锁。
      读写锁 对某一个资源的锁有两种共享S锁和都独占X锁

    可重入的概念:
    过度优化问题:编译器对于程序的优化,使得并不能让程序按照我们想象的方式来进行。
    例如单例模式:

    volatile T *pInst = 0;
    T *getInstance() {
    	if (pInst == NULL) {
    		lock();
    		if (pInst == NULL) {
    			pInst = new T;
    		}
    		unlock();
    	}
    	return pInst;
    }
    

    这个单例模式其实是有问题的,问题来源与CPU乱序执行。
    C++中new包含两个步骤:

    1. 分配内存
    2. 调用构造函数
      所以那个pInst=new T;包含三个步骤:
    3. 分配内存
    4. 调用构造函数
    5. 将内存首地址赋值给pInst
      其中第二步和第三步是可以颠倒顺序的。
      线程A 在先给pInst赋值后并没有完成构造,线程B这个时候调用getInstance会返回一个没有构造完成的T给用户使用。
      解决办法:
    #define barrier() __asm__ volatile ("lwsync")
    volatile T *pInst = 0;
    T *getInstance() {
    	if (pInst == NULL) {
    		lock();
    		if (pInst == NULL) {
    			T *temp = new T;
    			barrier();
    			pInst = temp;
    		}
    		unlock();
    	}
    	return pInst;
    }
    

    三种线程模型

    1. 一对一,每一个用户态的线程都对应一个内核里的线程,反之不成立
    2. 多对一, 多个用户态的线程对应一个内核里的线程, 存在问题:如果一个用户态线程阻塞,那么对应于同一内核线程的所有用户态线程都会阻塞。
    3. 多对多, 以上两种方式的结合,利用调度算法, 效率上不如一对一。
  • 相关阅读:
    后台服务器经典面试题
    Java英语面试题(核心知识篇)
    Java常用英语汇总(面试必备)
    字符压缩编码
    外排序
    基数排序
    Windows Server 2008 R2 部署服务
    LINUX中常用操作命令
    我的学习笔记_Windows_HOOK编程 2009-12-03 11:19
    CSDN-Code平台使用过程中的5点经验教训
  • 原文地址:https://www.cnblogs.com/Alruddy/p/9123496.html
Copyright © 2011-2022 走看看