《操作系统》之进程、线程、同步、死锁

文章目录

  • 《操作系统》之进程、线程、同步、死锁
    • ♢计算机基本组成结构
    • ♢进程管理
      • 进程
      • 进程的特性
      • 进程和程序的区别
      • 进程的基本状态和转换
      • 进程的构成
      • 进程控制块
      • 进程控制
      • 进程间通信
    • ♢线程
      • 线程和进程的关系
      • 线程的实现
      • 线程池
      • 线程的优势
    • ♢同步
    • ♢进程调度
      • 调度性能评价
      • 调度策略
    • ♢死锁
      • 产生死锁的必要条件
      • 死锁的处理方法
      • 死锁的检测与解除

♢计算机基本组成结构

硬件系统是构成计算机的物质基础,是计算机系统的核心。计算机硬件系统主要由运算器、存储器、控制器、输入设备和输出设备等主要功能部件组成,它们相互连接、相互作用,借以实现机器指令级的各种功能和特性。

针对输入/输出设备速度慢的特点,如果传输操作都要通过运算器,必将导致计算机效率不高的问题。现代计算机结构已转化为以存储器为中心的结构,借助通道、DMA方式,使I/O设备可以在控制器的较少干预下,完成与存储器间的数据交换,如下图所示。

运算器和控制器在逻辑上紧密关联,通常将两者制作在一块芯片上,这就是人们常说的中央处理器CPU)。CPU和内存储器也称为主机;输入/输出设备和外存储器又被统称为外部设备。

  • 运算器是进行数据处理即执行算术运算和逻辑运算的部件。
  • 控制器是计算机的管理结构和指挥中心,它协调计算机的各部件自动工作。控制器完成的工作实质上就是解释程序,它每次从存储器中读取一条指令,经过分析译码,产生一系列的控制信号,发往各个部件以控制它们的操作。连续不断、有条不紊地继续上述动作,即执行程序。
  • 存储器的主要功能是存放数据和程序。程序是计算机指令的有序集合,数据是计算机操作的对象,它们均以二进制的形式表示。为了实现程序的自动运行,数据和程序必须存放在内存储器中。内存储器由存储体、选址系统、读/写系统和存储时序控制线路构成。
  • 输入设备用于向计算机中输入数据和信息,它不仅是用户和计算机系统之间进行信息交换的主要装置,也是其他设备与计算机通信的桥梁。列如,操作命令、用户应答、数据、程序等都要依靠输入设备才能输入到计算机中。常见的输入设备有鼠标、键盘、数字化仪、扫描仪、数码相机、语音输入设备等。它们多是机电混合装置,与运算器、控制器和内存储器等纯电子部件相比,速度较慢。因此,一般需要通过被称为接口的电子部件与运算器、控制器和存储器相连接。
  • 输出设备是将计算处理的结果转换为人为或者其他设备能识别或接收的信息形式的装置。例如,显示器能将信息转换为字符、汉字、图形、图像,并在屏幕上显示;打印机能将文件打印到纸张上;绘图机可将图形绘制出来等。与输入设备一样,输出设备也多为机电装置,也需要通过接口与运算器、控制器和存储器相连接。

总线Bus)是计算机系统的互连结构之一,是一组信号线的集合,是计算机各部件间传输数据和命令的公共通道。

总线、总线设备、总线设备接口和总线控制器4部分组成总线系统


♢进程管理

并发执行的程序共享系统资源,共同对资源进行操作,系统中各个执行的程序产生了相互制约的新关系,出现“走走停停”的新情况,这些新情况均是程序在动态执行时产生的。用程序的这个静态概念已经无法正确描述并发程序执行过程中的这种特别情况,于是引入了“进程Process)”这一概念来反应程序动态执行过程中的特征。

将CPU切换到另外一个进程需要保存原来进程的状态并装入新进程的保存状态,这一任务被称为上下文切换

进程

进程最根本的属性是动态性并发性。关于进程的定义,有以下几种描述

  • 进程是程序的一次执行
  • 进程是一个程序及其数据在处理器上顺序执行时发生的活动
  • 进程是程序在一个数据集合上的运行过程,是系统进行资源分配和调度的一个独立单位

这里给出的定义为:进程是具有一定功能的程序在一个数据集合上的运作过程,它是系统进行资源分配和调度管理的一个可并发执行的基本单位。

进程的特性

  1. 动态性

    进程的实质是程序的一次执行过程,它由系统创建而产生,能够被调度而执行,因申请的共享资源被其他进程占用时而被暂停,完成任务后撤销。因此,动态性是进程最重要的特性。

  2. 并发性

    现代操作系统的重要特性是系统内多个进程可以并发执行,引入进程的目的也是为了使系统某个程序能够和其他进程的程序并发执行。

  3. 独立性

    进程是独立的,没有进程能影响另一个进程。目前,现代操作系统既有进程又有线程时,系统独立运行的基本单位变成线程,进程虽然不再是一个可执行的实体,但仍然是一个拥有资源的独立单位。

  4. 异步性

    进程由于共享资源和协同合作,因此产生了相互制约的关系,进程实体通过进程管理以异步的方式使用处理器和其他资源,系统必须通过统一调度,依据一定的算法来保证各个进程能够协同运行并共享处理器和其他资源。

  5. 结构特性

    为保证进程能够独立地在系统中和其他进程协同并共享资源,可通过给每个进程配置一个进程控制块Process Control BlockPCB)来描述进程的运动变化。系统中运行的进程实体通常由程序、数据和一个PCB三部分组成。

进程和程序的区别

  • 进程是程序的一次执行过程,而程序是一组指令的有序集合
  • 进程具有动态性、并发性、独立性和异步性,程序则不具备这些特性
  • 进程和程序并非是一一对应的
  • 进程的结构特性表明:进程包含程序、数据和进程控制块PCB

进程是动态的概念,而程序是静态的概念。程序可以长期保存,而进程是有短暂生命周期的,它动态地产生、变化和消亡。

进程的基本状态和转换

大多数系统的进程除了新建和终止外,都具有以下三种基本状态

  • 就绪(Ready)状态

    当进程已经分配到除处理器以外的所有必要的资源时,只要获得CPU就可以立即执行,此时的状态称为就绪状态。

  • 执行(Running)状态

    当进程已获得CPU时,其程序正在处理器上执行,此时的状态称为执行状态。在单处理系统中,只有一个进程处于执行态;在多处理系统中,可能有多个进程同时处于执行状态。执行的进程在分配的时间片用完后,转为就绪状态。

  • 阻塞(Blocked)状态

    正常执行的进程,由于等待某件事发生而无法执行时,便释放CPU而处于暂停状态,也称为等待状态。引起阻塞的事件有许多种,可能是请求I/O、申请缓冲区和等待某个信号、消息等。系统中同时处于阻塞状态的进程可以有多个,阻塞原因可以相同,也可能不同。

进程在存活期间,经常要求和其他进程共享资源,并发执行过程中相互之间会产生一定的制约关系,使进程的状态不断变化。3种基本状态间的转换如下图所示

进程的构成

进程由临界区、进程控制块、数据区和工作区组成

        | 临界区
进程控制块|| 数据区| 工作区
  • 临界区

    并发进程对共享资源的竞争形成了进程的互斥关系,这些资源有一个共同的特征即一次仅允许一个进程使用。通常将这类共享资源称为临界区。

  • 进程控制块

    PCB是系统用于查询和控制进程运行的档案

  • 数据区

    是进程执行时用到的数据

  • 工作区

    进程在核心态运行时的工作区称为核心栈,在用户态运行时的工作区为用户栈

进程控制块

PCB是进程存在的唯一标志。系统创建一个进程时,为它创建一个PCB;进程生命周期结束时,系统回收它的PCB。操作系统是通过PCB来确定进程是否存在。PCB的另外一个作用是为系统提供可并发执行的独立单位。PCB使一个在多道程序环境下不能独立运行的程序成为一个独立运行的基本单位,如果希望设置一个能够与其他进程并发执行的进程,建立PCB是首要前提。

PCB中包含以下基本信息:

  • 进程标识信息
  • 进程的状态
  • 进程特征
  • 进程位置及大小信息
  • 处理器的现场保留区
  • 进程资源清单
  • 进程同步与通信机制
  • 进程间的联系

进程控制

进程控制的主要任务是对进程的生命周期进行控制,包括进程的创建、撤销以及实现进程间的状态转换和进程通信等。

原语定义:原语Atomic Operation)是操作系统内核中用于完成某种特定功能的一个过程,此过程在执行过程中呈现原子特征,即执行过程不可再分割。也可称为原子性操作。现代操作系统往往是通过屏蔽中断的形式保证原语在执行时不可分。

进程创建

  1. 申请空闲PCB,为新进程获得内部标识信息
  2. 申请空闲PCB,为新进程获得内部标识信息
  3. 为新进程分配内存空间等系统资源
  4. 初始化PCB内容,包括进程标识、状态(常设为就绪)、优先级、程序地址、父进程PCB指针等
  5. 将新进程的PCB插入到PCB就绪队列中等待

一个进程创建一个新进程后有两种执行方式

  1. 父进程和子进程并发(同时)执行
  2. 父进程等待其子进程或全部子进程终止

建立子进程的地址空间也有两种方式:

  1. 子进程复制父进程的地址空间
  2. 将程序装入子进程的地址空间

进程撤销

进程撤销在有些书中称为进程终止,导致进程撤销的原因有很多,一般分为以下三种情况:

  1. 正常撤销:一个进程完成自己的任务,请求操作系统删除自己
  2. 异常终止:在进程运行过程中,如果出现某些错误或故障,会导致进程撤销
  3. 外部干扰:包括系统操作员或操作系统的干扰。产生的原因:一是可能是由于出现死锁,或者系统操作员或操作系统自身撤销该进程。二是由于父进程撤销,进程管理中规定当父进程撤销时操作系统会自动撤销其所有的子孙进程。

进程撤销原语的主要操作步骤如下:

  1. 从系统的PCB表中找到指定进程的PCB,若它正处于运行状态,则立即执行撤销命令,终止该进程的运行
  2. 回收该进程所占用的全部资源
  3. 若该进程为其他进程的父进程,则终止其名下的所有子孙进程,并释放它们占用的所有资源
  4. 将撤销进程的PCB从原来队列中删除

进程阻塞

进程阻塞在某些书上也称为进程等待。一个进程经常需要与其他进程进行通信,以确定自己的服务请求能否被保证,申请的资源是否空闲。

进程阻塞原语的主要操作步骤如下:

  1. 立即终止当前进程的执行
  2. 将该进程运行的处理器信息保存在自己的PCB保护区中保存,以便重新运行时恢复终止时的现场
  3. 将该进程现行状态由运行态改成阻塞态,同时将该进程插入阻塞队列中
  4. 转到进程调度程序,重新从就绪队列中选择一个合适的进程投入运行

进程唤醒

当阻塞进程等待的资源出现时,则有另外的、与本阻塞进程相关的进程调用唤醒原语,将等待该资源的进程唤醒。注意,阻塞进程不能唤醒自己。阻塞进程的唤醒必须由唤醒原语执行。

进程唤醒原语的主要操作步骤如下:

  1. 将阻塞进程从相应的阻塞队列中移出
  2. 将该进程运行状态改成就绪状态
  3. 如果刚被唤醒的进程比当前运行进程的优先级高,则设置重新调整标志

进程间通信

进程间通信是指进程之间可以直接以较高的速率传输较多的数据和信息交换方式。

常见的3种进程通信方式为消息传递系统、共享存储器系统和管道通信系统。


♢线程

线程Thread)是进程中实施调度和分配的基本单位。

如果将进程理解为在逻辑上操作系统所完成的任务,而线程则表示完成该任务的许多可能的子任务中的一个。操作系统提供线程的目的就是为了方便而有效地实现并发处理。

与进程相比,线程也有若干状态,例如运行状态、阻塞状态、就绪状态和终止状态等。

线程和进程的关系

  • 一个进程可以有多个线程,但是至少有一个线程;而一个线程只能在一个进程的地址空间内活动
  • 资源分配给进程,同一进程的所有线程共享该进程的所有资源
  • CPU分配给线程,即真正在处理器运行的是线程
  • 线程在执行过程中需要协作同步,不同进程的线程间要利用消息通信的办法实现同步

线程的实现

每个线程都有一个thread结构,即线程控制块,用于保存自己的私有信息,主要由线程ID、程序计数器,寄存器集合和堆栈组成。它与属于同一进程的其他线程共享其他代码段,数据段和其他操作系统资源。

现代操作系统大部分提供对用户和核心线程的支持,由此带来不同的多线程实现方式。

在介绍多线程实现方式之前,先介绍一下用户线程和内核线程的概念。一般有两种主要的线程实现方法,用户级线程(ULT)和核心级线程(KLT)。

  • 用户级线程ULT):在内核之上支持用户级线程,并在用户层通过线程库来实现。线程库提供对线程的创建、调度和管理等支持,而不需要操作系统内核的支持。
  • 核心级线程KLT):由操作系统直接支持,内核在其空间内执行线程的创建、调度和管理。

线程池

实现线程池的设计思想是:在创建一个进程时,相应地创建若干个线程,将它们放在一个缓冲池中,这些线程在等待工作。当服务器接收到一个请求时,系统就唤醒其中的一个线程,并将请求传给它,由这个线程进行服务。当完成任务后,线程重新被放入线程池中,等待下面新的请求和服务。如果线程池中没有可用的线程,服务器就要等待,直到有一个线程被释放。

使用线程池的好处如下:

  • 利用现成线程池中的线程去完成某种服务比等待创建一个线程后再去服务更快
  • 线程池限定了任何时候存在的线程数量。这一点对于那些不支持大量线程的系统来说非常重要

线程的优势

多线程编程具有以下优点:

  • 响应度高:如果对一个交互式应用程序采用多线程,即使其某个部分阻塞或执行较长的操作,由于是并发执行,该程序仍然能够执行,增加了对用户的响应速度。
  • 资源共享:线程默认共享它们所属进程的内存和资源,代码共享的优点是能够允许一个应用程序在同一个地址空间有多个不同的活动线程。
  • 经济:进程创建所需的内存和资源的分配成本比较高,由于线程的引入,使同一进程下的所有线程能够共享该进程下的所有资源,因此线程的创建和上下文的切换比较经济,易于调度,开销少
  • 效能高:目前,硬件结构发生了很大变化,多处理器体系结构的系统越来越多,多线程的优点是能够便于每个线程能并行在不同的处理器上。可以充分发挥多处理处理器的效能,实现用户应用程序的并发。

♢同步

进程间的相互关系主要分为以下3种:

  • 同步:所谓同步是指同一组相互协同的进程,在完成同一任务,对某些共享资源进行操作时,为协调资源占用而相互等待、相互交换信息所产生的制约关系。
  • 互斥:所谓互斥是指并发进程间因相互竞争使用独占资源所产生的制约关系
  • 通信:多个进程间为合作完成一项工作,需要直接交换信息。通常,将进程间的信息交换称为进程间通信。

并行执行的多个线程会竞争使用某些共享资源,如果没有相应的规则来加以约束,其执行结果是不确定的,多个进程共享这种资源时必须互斥执行。

  • 临界资源Critical Resource,CR)

    并发进程对共享资源的竞争使用形成各个进程间的互斥关系,此类资源有一个共同点,就是一次只能允许一个进程使用。

  • 临界区Critical Section,CS)

    考虑到一个系统中有多个进程,通常定义每个进程中访问或者使用临界资源的那段程序代码就叫做临界区。

经典的进程同步问题

  • 生产者和消费者问题
  • 读者和写者问题
  • 理发师问题
  • 哲学家就餐问题

♢进程调度

所谓进程调度,就是通过某种规则或算法从阻塞(等待)进程队列中选取一个进程投入运行。调度是操作系统的基本功能之一,几乎所有的计算机资源在使用前都需要调度。当然,CPU是首要的计算机资源之一,因此CPU调度是操作系统设计的核心问题。

出现抢占调度的情况有:新进程到达、出现中断且将原来处于阻塞状态下的进程转变成就绪、可能用完规定的时间片等。

调度性能评价

  • CPU的利用率

    系统设计要尽可能充分发挥CPU的性能,特别是当CPU的价格非常昂贵时,需要让它尽可能“忙”。一般系统CPU的利用率在40%~90%之间。

  • 吞吐量

    衡量单位时间内CPU完成作业数量的一个指标,对于长进程,吞吐量可能是每个小时一个进程,对于短进程事务,可能为每秒十几个进程。

  • 周转时间

    从进程提交到进程运行结束的时间间隔称为周转时间

  • 就绪等待时间

    CPU调度算法并不影响进程运行和执行I/O的时间,它只影响进程在就绪队列中等待所消耗的时间,因此系统设计时可简单考虑每个进程在就绪队列的等待时间

  • 响应时间

    不同的系统要求不同的响应时间,实时系统对响应时间的要求很高。对于交互式系统,周转时间并不是最好的评价指标。这里定义响应时间为从提交申请到产生响应的时间为响应时间,是系统开始响应所需要的时间。

调度策略

通常,系统及其目标决定了所采用的调度策略。下面描述一些最常用的CPU调度策略。

  • 先来先服务调度算法FCFS

  • 短作业优先调度算法Shortest-Job-FirtstSJF

    抢占式SJF调度也被称为最短剩余时间优先调度(Shortest Remaining Time First, SRTF

  • 优先级调度算法

    • 静态优先级,静态优先级调度算法是指在创建进程时就确定下来,而且在整个运行期间优先级是维持不变的
    • 动态优先级,动态优先级是随着进程的推进而不断变化的

    非抢占式优先级法和抢占式优先级法

  • 轮转调度算法Round-RobinRR),适用于分时系统,时间片

    时间片的大小通常由以下几个因素决定:

    1. 系统的响应时间
    2. 系统的相遇时间
    3. 进程周转时间
    4. 时间片大小和CPU主频有关
  • 多级队列调度算法Multilevel-QueueMQ

    如果可以很方便地对进程分组,可以采用另外一种调度算法。例如,一种通用的分组方法是将进程分为前台(或交互式)进程和后台(或批处理)进程,可以使用RR算法调度前台队列,使用FCFS调度后台队列。另外,必须要在队列间进行调度,这种调度通常实现为权限固定的抢占式调度

♢死锁

死锁是进程死锁的简称,是两个或多个进程无限期地等待永远都不会发生的条件,系统处在停滞状态。

产生死锁的必要条件

在系统中,如果以下4个条件同时成立,死锁就会发生

  1. 互斥条件:必须至少有一个资源以非共享的方式被进程持有
  2. 持有并等待条件:进程至少必须持有一个资源且等待获取另外的当前被其他进程持有的资源
  3. 不可抢占条件:不可以抢占资源
  4. 循环等待条件:系统必然存在一条由两个以上的进程组成的循环链,链中的每个进程都在等待相关进程所占用的资源

死锁的处理方法

从原理上讲,有三种方式可以处理死锁问题:

  1. 可以使用协议来预防或避免死锁,确保系统绝不可能进入死锁状态
  2. 可以允许系统进入死锁状态,然后检测它,并加以处理克服它,恢复系统运行
  3. 将死锁忽略不计,认为死锁不可能在系统内发生,有些操作系统 就是这么做的。

银行家算法安全序列分配。

死锁的检测与解除

死锁的检测

如果系统没有采用死锁预防或死锁避免算法,就有可能发生死锁。在这种环境下,系统必须提供:

  • 用于检测系统状态以确定是否发生死锁的算法
  • 从死锁中恢复的算法
  1. 每种资源都只有单个的系统

    如果每种资源都只有一个,可修改资源分配图来定义一种死锁检测算法,通常被称为等待图。为了降低计算开销,在此从资源分配图中移除资源结点和相应的边。

  2. 资源有多个的系统

    与银行家算法类似的数据结构

死锁的解除

当检测算法确定系统中存在死锁时,可以有多种选择。可以通知操作员发生了死锁,让操作员手工解除死锁;也可以使系统自动从死锁中恢复。有两种解除死锁的方法,一种简单地异常终止一个或多个进程来打断这个循环等待;另一种是从一个或多个死锁的进程中抢占资源。

  1. 进程终止

    为了通过异常终止来消除死锁,一般有两种方法可以选择。在这两种方法中,系统都需要回收被异常终止进程所持有的所有资源。

    • 异常终止所有的死锁进程:这种方法无疑可以打断死锁循环,但是代价高昂——这些进程可能已经计算了很长一段时间,而且必须丢掉这些计算结果并且稍后可能需要重新计算。
    • 每次异常终止一个进程直到消除死锁循环:这种方法会导致相当可观的开销,因为每次终止进程之后都需要执行一次死锁解除算法来确定是否仍然有进程死锁
  2. 抢占资源

    通过采用抢占资源的方式来消除死锁,不断抢占进程的资源并将这些资源分配给其他进程,直到打破死锁循环。如果需要利用抢占来解除死锁,需要应付3件事:

    • 选择一个进程:求代价最小化
    • 回滚:如果抢占了一个进程的资源,那么这个进程将不再继续执行;它失去了所需的一些资源。通常,必须将进程回滚到某种安全状态,并保存相关信息,使其能够从这个状态重新开始。
    • “饥饿”:确定怎样将不发生“饥饿”,更确切地说,怎样保证不总是从同一个进程中抢占资源。

参考资料《操作系统原理与实践》邹鹏著

提示:本博客仅供学习和参考

《操作系统》之进程、线程、同步、死锁相关推荐

  1. 进程/线程同步的方式和机制,进程间通信

    一.进程/线程间同步机制. 临界区.互斥区.事件.信号量四种方式 临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别 1.临界区: ...

  2. 4.19 python 网络编程和操作系统部分(TCP/UDP/操作系统概念/进程/线程/协程) 学习笔记

    文章目录 1 网络编程概念 1)基本概念 2)应用-最简单的网络通信 2 TCP协议和UDP协议进阶(网络编程) 1)TCP协议和UDP协议基于socket模块实现 2)粘包现象 3)文件上传和下载代 ...

  3. 计算机操作系统——经典进程的同步问题

    计算机操作系统--信号量机制与经典进程的同步问题 信号量机制 随着发展,信号量从整型信号量经记录型信号量,进而发展为"信号量集"机制. 一般来说,信号量的值与相应的资源的使用情况有 ...

  4. linux进程线程同步之 - POSIX线程互斥锁

    POSIX线程互斥锁 使用范围:线程同步 本文转自:http://blog.csdn.net/jiebaoabcabc/article/details/37914769 一.函数介绍 1.初始化互斥锁 ...

  5. 操作系统之进程的同步机制

    文章目录 进程的同步机制 一.基本概念 1.进程同步机制的概念 2.为何要引入进程同步机制 3.临界资源 4.临界区 二.进程同步与互斥关系 1.同步 2.互斥 三.进程同步机制的四个基本原则 1.空 ...

  6. 【操作系统】进程/线程模型

    1. 进程的基本概念 1.1 多道程序设计(Multi-Programming) 首先从多道程序设计开始,以便更好的理解进程的必要性. 在早期没有多道程序设计之前,操作系统只有一个物理程序计数器,这样 ...

  7. socket编程和进程线程同步跟新

    博主认为如果这两个分开更新的话,博主不知道要更新多久,所以不如大胆一点,进程线程与socket网络编程一起更新,希望能快一点结束这里的故事从而开启更多新篇章.

  8. 操作系统总结--进程,线程

    进程 进程(进程实体)由PCB()Process Control Block).程序段.数据段三 部分组成. 对用户而言,我们能看到一个个PID,而对操作系统而言,底层需要处理的是一个个PCB. PC ...

  9. 【操作系统之哲学导论】进程/线程管理篇

    文章目录 基础原理 操作系统导论 1.程序是如何运行的 2.操作系统的核心功能 操作系统基本概念 1.计算机硬件基本知识 2.用户态和内核态 3.进程 4.系统调用 5.壳 进程管理 进程 进程调度 ...

  10. C#并行编程(6):线程同步面面观

    理解线程同步 线程的数据访问 在并行(多线程)环境中,不可避免地会存在多个线程同时访问某个数据的情况.多个线程对共享数据的访问有下面3种情形: 多个线程同时读取数据: 单个线程更新数据,此时其他线程读 ...

最新文章

  1. Java数据库foreign,mysql中的外键foreign key 作者:Java_xb
  2. python知识体系_python学习知识体系梳理
  3. http 三种认证方式 Basic Session Token 简介
  4. 简单的同步Socket程序服务端
  5. ListView常用属性、方法
  6. stm32寄存器版学习笔记04 定时计数器中断
  7. 【C++】类型转换(const_cast、dynamic_cast、static_cast、reinterpret_cast)
  8. 每天一个linux命令(10):more命令
  9. win7桌面运行html,手把手教你win7电脑如何运行config的操作教程
  10. vscode之parcel清空dist目录
  11. 第13章 集成学习和随机森林 学习笔记中 oob
  12. 几款好用的谷歌卫星地图下载器
  13. 辞职日记----记录31岁的程序员跳槽心态
  14. 2017年上半年软件设计师考试真题及答案(上午+下午)免费
  15. Android App赞赏功能,微信公众号赞赏功能升级:作者可直接收到赞赏, iOS安卓均可用...
  16. DBeaver出现:The Network Adapter could not establish the connection 已解决
  17. 【面试必过系列,15个经典面试问题及回答思路
  18. CMakeLists.txt范例
  19. xmind文件不见了处理方法
  20. 蚂蚁p8多少股票_蚂蚁金服上市了,小编不想努力了。

热门文章

  1. Python之集合(综合练习)
  2. Activiti流程引擎架构概述
  3. 跨境必看:跨境支付问题以及热门跨境支付方式的优劣势分析!
  4. php 字符串加密解密
  5. 走进小作坊(二十)----商道:胡雪岩叱咤商场的经营智慧
  6. 对数正态随机数c语言程序,对数正态随机数
  7. Annoying day
  8. 用向量求一个点到一条直线垂足的坐标
  9. 安卓app开发方案_简谈企业最常用的三种安卓app开发语言
  10. C++解决八皇后问题