操作系统概述 操作系统(Operating System,OS)是管理计算机硬件与软件资源的计算机程序,是计算机系统的核心与基石。它负责管理与配置内存、决定系统资源供需的优先次序、控制输入设备与输出设备、操作网络与管理文件系统等基本任务。
操作系统的主要功能
进程管理 :负责进程的创建、调度、同步和通信
内存管理 :负责内存的分配、回收和保护
文件系统 :负责文件的存储、组织和访问
设备管理 :负责设备的分配、控制和驱动
用户接口 :提供用户与操作系统交互的方式
操作系统的分类
批处理操作系统 :按批量处理作业,如早期的 IBM OS/360
分时操作系统 :允许多个用户同时使用计算机,如 UNIX、Linux
实时操作系统 :对时间有严格要求,如 VxWorks、RTOS
网络操作系统 :管理网络资源,如 Windows Server、Linux
分布式操作系统 :管理分布式系统资源,如 Amoeba、Mach
进程管理 进程概念 进程是程序的一次执行过程,是操作系统进行资源分配和调度的基本单位。
进程与程序的区别
程序 :静态的,是一组指令的集合
进程 :动态的,是程序的执行过程
一个程序可以对应多个进程,一个进程可以包含多个程序
进程控制块(PCB) 进程控制块是操作系统用于管理进程的核心数据结构,包含进程的所有信息:
进程标识符(PID)
进程状态
程序计数器(PC)
寄存器集合
内存管理信息
文件描述符表
进程优先级
进程间通信信息
进程状态 进程在其生命周期中会经历不同的状态,典型的进程状态包括:
运行态(Running) :进程正在 CPU 上执行
就绪态(Ready) :进程已准备好执行,等待分配 CPU
阻塞态(Blocked) :进程等待某事件发生(如 I/O 完成)
创建态(New) :进程正在被创建
终止态(Terminated) :进程执行完毕或被终止
进程调度 进程调度是操作系统按照一定的算法从就绪队列中选择一个进程分配 CPU。
调度算法
先来先服务(FCFS) :按照进程到达的先后顺序调度
最短作业优先(SJF) :选择估计运行时间最短的进程调度
最短剩余时间优先(SRTF) :SJF 的抢占式版本
优先级调度 :按照进程的优先级调度
时间片轮转(RR) :为每个进程分配一个时间片,时间片用完后切换到下一个进程
多级反馈队列调度 :结合了多种调度算法的优点
示例:时间片轮转调度算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 #include <stdio.h> #include <stdlib.h> typedef struct Process { int pid; int arrival_time; int burst_time; int remaining_time; int waiting_time; int turnaround_time; } Process; void round_robin_scheduling (Process processes[], int n, int quantum) { int current_time = 0 ; int completed = 0 ; int *queue = (int *)malloc (n * sizeof (int )); int front = 0 , rear = 0 ; int *visited = (int *)calloc (n, sizeof (int )); for (int i = 0 ; i < n; i++) { if (processes[i].arrival_time == 0 ) { queue [rear++] = i; visited[i] = 1 ; } } while (completed < n) { int current_process = queue [front++]; if (processes[current_process].remaining_time > quantum) { current_time += quantum; processes[current_process].remaining_time -= quantum; } else { current_time += processes[current_process].remaining_time; processes[current_process].remaining_time = 0 ; completed++; processes[current_process].turnaround_time = current_time - processes[current_process].arrival_time; processes[current_process].waiting_time = processes[current_process].turnaround_time - processes[current_process].burst_time; } for (int i = 0 ; i < n; i++) { if (processes[i].arrival_time <= current_time && processes[i].remaining_time > 0 && !visited[i]) { queue [rear++] = i; visited[i] = 1 ; } } if (processes[current_process].remaining_time > 0 ) { queue [rear++] = current_process; } } free (queue ); free (visited); } void print_results (Process processes[], int n) { printf ("PID\t到达时间\t运行时间\t等待时间\t周转时间\n" ); for (int i = 0 ; i < n; i++) { printf ("%d\t%d\t\t%d\t\t%d\t\t%d\n" , processes[i].pid, processes[i].arrival_time, processes[i].burst_time, processes[i].waiting_time, processes[i].turnaround_time); } float avg_waiting_time = 0 , avg_turnaround_time = 0 ; for (int i = 0 ; i < n; i++) { avg_waiting_time += processes[i].waiting_time; avg_turnaround_time += processes[i].turnaround_time; } avg_waiting_time /= n; avg_turnaround_time /= n; printf ("\n平均等待时间: %.2f\n" , avg_waiting_time); printf ("平均周转时间: %.2f\n" , avg_turnaround_time); } int main () { int n, quantum; printf ("输入进程数量: " ); scanf ("%d" , &n); Process *processes = (Process *)malloc (n * sizeof (Process)); for (int i = 0 ; i < n; i++) { printf ("\n输入进程 %d 的到达时间和运行时间: " , i + 1 ); scanf ("%d %d" , &processes[i].arrival_time, &processes[i].burst_time); processes[i].pid = i + 1 ; processes[i].remaining_time = processes[i].burst_time; processes[i].waiting_time = 0 ; processes[i].turnaround_time = 0 ; } printf ("\n输入时间片大小: " ); scanf ("%d" , &quantum); round_robin_scheduling(processes, n, quantum); print_results(processes, n); free (processes); return 0 ; }
进程同步 进程同步是指协调并发进程的执行,使它们按照一定的顺序或规则访问共享资源,避免数据不一致或竞态条件。
临界区问题 临界区是进程中访问共享资源的代码段。解决临界区问题需要满足以下条件:
互斥 :同一时间只能有一个进程进入临界区
前进 :如果没有进程在临界区,应允许一个等待的进程进入
有限等待 :进程在进入临界区前的等待时间是有限的
同步机制
信号量(Semaphore) :一种用于控制访问共享资源的计数器
互斥锁(Mutex) :用于实现互斥的特殊信号量
条件变量(Condition Variable) :用于线程间的通信和同步
管程(Monitor) :将共享资源和操作封装起来的高级同步机制
示例:使用信号量解决生产者-消费者问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #define BUFFER_SIZE 5 int buffer[BUFFER_SIZE];int in = 0 , out = 0 ;sem_t empty; sem_t full; sem_t mutex; void *producer (void *arg) { int item; for (int i = 0 ; i < 10 ; i++) { item = rand() % 100 ; sem_wait(&empty); sem_wait(&mutex); buffer[in] = item; printf ("生产者生产: %d, 放入位置: %d\n" , item, in); in = (in + 1 ) % BUFFER_SIZE; sem_post(&mutex); sem_post(&full); sleep(rand() % 2 ); } return NULL ; } void *consumer (void *arg) { int item; for (int i = 0 ; i < 10 ; i++) { sem_wait(&full); sem_wait(&mutex); item = buffer[out]; printf ("消费者消费: %d, 取出位置: %d\n" , item, out); out = (out + 1 ) % BUFFER_SIZE; sem_post(&mutex); sem_post(&empty); sleep(rand() % 3 ); } return NULL ; } int main () { pthread_t producer_thread, consumer_thread; sem_init(&empty, 0 , BUFFER_SIZE); sem_init(&full, 0 , 0 ); sem_init(&mutex, 0 , 1 ); pthread_create(&producer_thread, NULL , producer, NULL ); pthread_create(&consumer_thread, NULL , consumer, NULL ); pthread_join(producer_thread, NULL ); pthread_join(consumer_thread, NULL ); sem_destroy(&empty); sem_destroy(&full); sem_destroy(&mutex); return 0 ; }
进程通信 进程通信是指进程之间交换信息的机制。
分类
低级通信机制 :信号、管道
高级通信机制 :消息队列、共享内存、套接字
常见通信方式
管道(Pipe) :半双工通信,只能在父子进程或兄弟进程之间使用
命名管道(FIFO) :可以在不相关进程之间使用
消息队列(Message Queue) :存储消息的链表,支持消息的优先级
共享内存(Shared Memory) :进程共享同一块物理内存,是最快的通信方式
信号量(Semaphore) :主要用于同步,也可用于简单的通信
套接字(Socket) :用于网络通信,可以在不同主机上的进程之间通信
线程 线程是进程内的一个执行单元,是 CPU 调度的基本单位。
线程与进程的区别
资源分配 :进程是资源分配的基本单位,线程共享进程的资源
调度 :线程是 CPU 调度的基本单位
并发性 :一个进程内的多个线程可以并发执行
系统开销 :创建和切换线程的开销比进程小
线程的分类
用户级线程 :由用户程序管理,操作系统不可见
内核级线程 :由操作系统管理
混合级线程 :结合了用户级线程和内核级线程的优点
内存管理 内存管理概述 内存管理负责计算机内存的分配、回收和保护,确保多道程序能够高效、安全地运行。
内存管理的主要功能
连续分配管理方式 连续分配是指为进程分配连续的内存空间。
单一连续分配
内存分为系统区和用户区
一次只允许一个用户进程运行
适用于单用户、单任务操作系统
固定分区分配
将内存划分为固定大小的分区
每个分区只能容纳一个进程
存在内部碎片
动态分区分配
根据进程的实际需要动态分配内存
存在外部碎片
分配算法:首次适应算法、最佳适应算法、最坏适应算法、邻近适应算法
非连续分配管理方式 非连续分配是指为进程分配不连续的内存空间。
分页存储管理
将物理内存划分为大小相等的页框(Page Frame)
将进程的逻辑地址空间划分为大小相等的页(Page)
通过页表(Page Table)实现页到页框的映射
分段存储管理
将进程的逻辑地址空间划分为若干个段(Segment)
每个段对应一个逻辑单位(如函数、数组)
通过段表(Segment Table)实现段到物理内存的映射
段页式存储管理
结合了分页和分段的优点
先将逻辑地址空间划分为段,再将每个段划分为页
通过段表和页表实现地址映射
虚拟内存管理 虚拟内存是指操作系统为进程提供的一个比实际物理内存大得多的虚拟地址空间。
虚拟内存的特征
多次性 :进程可以分多次调入内存
对换性 :进程可以在内存和外存之间对换
虚拟性 :为进程提供大于实际物理内存的虚拟地址空间
虚拟内存的实现方式
请求分页存储管理
请求分段存储管理
请求段页式存储管理
页面置换算法
最佳置换算法(OPT) :选择未来最长时间不使用的页面置换
先进先出置换算法(FIFO) :选择最早调入的页面置换
最近最久未使用置换算法(LRU) :选择最近最久未使用的页面置换
时钟置换算法(Clock) :FIFO 的改进版本
最不常用置换算法(LFU) :选择访问次数最少的页面置换
示例:请求分页存储管理的页表结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 #include <stdio.h> #include <stdlib.h> #define PAGE_SIZE 4096 #define PHYSICAL_MEMORY_SIZE 16384 #define NUM_PAGES (PHYSICAL_MEMORY_SIZE / PAGE_SIZE) typedef struct PageTableEntry { int valid; int frame_number; int dirty; int reference; } PageTableEntry; typedef struct PageTable { PageTableEntry *entries; int num_entries; } PageTable; PageTable* create_page_table (int num_entries) { PageTable *page_table = (PageTable *)malloc (sizeof (PageTable)); page_table->num_entries = num_entries; page_table->entries = (PageTableEntry *)calloc (num_entries, sizeof (PageTableEntry)); return page_table; } void destroy_page_table (PageTable *page_table) { free (page_table->entries); free (page_table); } int translate_address (PageTable *page_table, int logical_address) { int page_number = logical_address / PAGE_SIZE; int offset = logical_address % PAGE_SIZE; if (page_number < 0 || page_number >= page_table->num_entries) { printf ("页号越界:%d\n" , page_number); return -1 ; } PageTableEntry *entry = &page_table->entries[page_number]; if (!entry->valid) { printf ("页面故障:页号 %d 不在内存中\n" , page_number); entry->valid = 1 ; entry->frame_number = page_number % NUM_PAGES; printf ("页面 %d 已调入页框 %d\n" , page_number, entry->frame_number); } entry->reference = 1 ; int physical_address = entry->frame_number * PAGE_SIZE + offset; printf ("逻辑地址: %d (页号: %d, 偏移: %d) -> 物理地址: %d\n" , logical_address, page_number, offset, physical_address); return physical_address; } int main () { PageTable *page_table = create_page_table(10 ); int logical_addresses[] = {1000 , 5000 , 10000 , 15000 , 20000 }; int num_addresses = sizeof (logical_addresses) / sizeof (logical_addresses[0 ]); for (int i = 0 ; i < num_addresses; i++) { int logical_address = logical_addresses[i]; int physical_address = translate_address(page_table, logical_address); if (physical_address != -1 ) { printf ("地址转换成功\n" ); } else { printf ("地址转换失败\n" ); } printf ("\n" ); } destroy_page_table(page_table); return 0 ; }
文件系统 文件系统概述 文件系统是操作系统用于管理文件的一套机制,负责文件的存储、组织和访问。
文件的概念 文件是具有文件名的一组相关数据的集合。
文件的属性
文件名
文件类型
文件大小
文件位置
文件保护
文件时间(创建时间、修改时间、访问时间)
文件的操作
创建文件(create)
打开文件(open)
读文件(read)
写文件(write)
关闭文件(close)
删除文件(delete)
重命名文件(rename)
文件的组织结构 文件的组织结构是指文件的逻辑结构,即用户看到的文件组织形式。
无结构文件(流式文件)
文件是字节流的集合
没有固定的记录结构
适用于文本文件、二进制文件等
有结构文件(记录式文件)
文件由若干个记录组成
每个记录包含若干个字段
适用于数据库文件等
文件的存储结构 文件的存储结构是指文件在物理存储设备上的组织形式。
连续分配
文件的所有块连续存储在物理磁盘上
优点:顺序访问速度快
缺点:存在外部碎片,文件扩展困难
链接分配
文件的块分散存储在物理磁盘上,通过指针链接
优点:没有外部碎片,文件扩展方便
缺点:顺序访问速度慢,可靠性差
索引分配
为每个文件创建一个索引块,记录文件所有块的位置
优点:支持随机访问,文件扩展方便
缺点:需要额外的存储空间存储索引块
文件系统的实现 文件系统的实现包括文件控制块(FCB)、目录结构和存储空间管理。
文件控制块(FCB) 文件控制块是操作系统用于管理文件的核心数据结构,包含文件的所有属性。
目录结构
单级目录结构 :所有文件都放在一个目录中
两级目录结构 :分为主目录和用户目录
树形目录结构 :目录组织成树形结构,支持路径名
图形目录结构 :树形目录结构的扩展,支持目录链接
存储空间管理
空闲表法 :记录空闲的磁盘块
空闲链表法 :将空闲磁盘块链接成链表
位示图法 :用位表示磁盘块的使用情况
成组链接法 :结合了空闲表法和空闲链表法的优点
文件系统的操作 示例:使用系统调用操作文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main () { int fd; char buffer[1024 ]; ssize_t bytes_read, bytes_written; fd = open("test.txt" , O_CREAT | O_WRONLY | O_TRUNC, 0644 ); if (fd == -1 ) { perror("open" ); exit (EXIT_FAILURE); } const char *text = "Hello, Operating System!\nThis is a test file.\n" ; bytes_written = write(fd, text, strlen (text)); if (bytes_written == -1 ) { perror("write" ); close(fd); exit (EXIT_FAILURE); } printf ("写入了 %ld 字节\n" , bytes_written); close(fd); fd = open("test.txt" , O_RDONLY); if (fd == -1 ) { perror("open" ); exit (EXIT_FAILURE); } printf ("\n文件内容:\n" ); while ((bytes_read = read(fd, buffer, sizeof (buffer))) > 0 ) { write(STDOUT_FILENO, buffer, bytes_read); } if (bytes_read == -1 ) { perror("read" ); close(fd); exit (EXIT_FAILURE); } close(fd); if (unlink("test.txt" ) == -1 ) { perror("unlink" ); exit (EXIT_FAILURE); } printf ("\n文件已删除\n" ); return 0 ; }
设备管理 设备管理概述 设备管理负责计算机系统中各种 I/O 设备的分配、控制和驱动,确保设备能够高效、可靠地工作。
设备的分类
按传输速率 :低速设备、中速设备、高速设备
按信息交换单位 :字符设备、块设备
按设备共享属性 :独占设备、共享设备、虚拟设备
设备管理的主要功能
设备分配与回收
设备控制
缓冲管理
设备独立性
设备驱动程序管理
I/O 控制方式 I/O 控制方式是指 CPU 与 I/O 设备之间的信息交换方式。
程序直接控制方式 :CPU 不断查询设备状态,直到 I/O 完成
中断驱动方式 :设备完成 I/O 后向 CPU 发送中断信号
DMA 方式 :直接内存访问,设备与内存直接交换数据,CPU 只需初始化和完成时处理
通道控制方式 :通过通道(一种专用的 I/O 处理器)控制 I/O 设备
设备驱动程序 设备驱动程序是操作系统与 I/O 设备之间的接口,负责将操作系统的请求转换为设备能够理解的命令。
设备驱动程序的主要功能
初始化设备
处理设备中断
实现设备的各种操作(如读、写)
管理设备的电源
设备独立性 设备独立性是指应用程序与实际使用的物理设备无关,提高了系统的可移植性和灵活性。
缓冲管理 缓冲是指在内存中为 I/O 设备分配的一块临时存储区域,用于缓解 CPU 与 I/O 设备之间速度不匹配的问题。
缓冲的类型
单缓冲 :只有一个缓冲区
双缓冲 :有两个缓冲区,一个用于输入,一个用于输出
循环缓冲 :多个缓冲区组成一个循环队列
缓冲池 :由多个缓冲区组成的公用缓冲区域
磁盘管理 磁盘管理负责磁盘的调度、格式化和维护。
磁盘调度算法
先来先服务(FCFS) :按照请求到达的先后顺序处理
最短寻道时间优先(SSTF) :选择离当前磁头位置最近的请求处理
扫描算法(SCAN) :磁头在磁盘上双向移动,处理经过的所有请求
循环扫描算法(C-SCAN) :磁头只向一个方向移动,处理经过的所有请求
LOOK 算法 :SCAN 算法的改进,磁头只移动到最远的请求位置
C-LOOK 算法 :C-SCAN 算法的改进,磁头只移动到最远的请求位置
示例:使用扫描算法(SCAN)进行磁盘调度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 #include <stdio.h> #include <stdlib.h> int compare (const void *a, const void *b) { return (*(int *)a - *(int *)b); } void scan_disk_scheduling (int requests[], int n, int current_position, int direction) { int total_seek_time = 0 ; int *left = (int *)malloc (n * sizeof (int )); int *right = (int *)malloc (n * sizeof (int )); int left_count = 0 , right_count = 0 ; for (int i = 0 ; i < n; i++) { if (requests[i] < current_position) { left[left_count++] = requests[i]; } else { right[right_count++] = requests[i]; } } qsort(left, left_count, sizeof (int ), compare); qsort(right, right_count, sizeof (int ), compare); printf ("磁盘调度顺序: %d" , current_position); if (direction == 1 ) { for (int i = 0 ; i < right_count; i++) { total_seek_time += abs (right[i] - current_position); current_position = right[i]; printf (" -> %d" , current_position); } if (left_count > 0 ) { total_seek_time += abs (199 - current_position); current_position = 199 ; printf (" -> %d" , current_position); for (int i = left_count - 1 ; i >= 0 ; i--) { total_seek_time += abs (left[i] - current_position); current_position = left[i]; printf (" -> %d" , current_position); } } } else { for (int i = left_count - 1 ; i >= 0 ; i--) { total_seek_time += abs (left[i] - current_position); current_position = left[i]; printf (" -> %d" , current_position); } if (right_count > 0 ) { total_seek_time += abs (current_position - 0 ); current_position = 0 ; printf (" -> %d" , current_position); for (int i = 0 ; i < right_count; i++) { total_seek_time += abs (right[i] - current_position); current_position = right[i]; printf (" -> %d" , current_position); } } } printf ("\n总寻道时间: %d\n" , total_seek_time); free (left); free (right); } int main () { int n, current_position, direction; printf ("输入请求数量: " ); scanf ("%d" , &n); int *requests = (int *)malloc (n * sizeof (int )); printf ("输入请求的磁道号: " ); for (int i = 0 ; i < n; i++) { scanf ("%d" , &requests[i]); } printf ("输入当前磁头位置: " ); scanf ("%d" , ¤t_position); printf ("输入移动方向 (1: 向右, 0: 向左): " ); scanf ("%d" , &direction); scan_disk_scheduling(requests, n, current_position, direction); free (requests); return 0 ; }
用户接口 用户接口是用户与操作系统交互的桥梁,提供了用户使用操作系统功能的方式。
命令接口 命令接口是用户通过输入命令来操作计算机的接口。
联机命令接口
交互式命令接口 :用户输入一条命令,系统执行后返回结果
命令行解释器 :负责解释和执行用户输入的命令
脱机命令接口
批处理命令接口 :用户将命令写入批处理文件,系统批量执行
程序接口 程序接口是应用程序与操作系统之间的接口,通过系统调用(System Call)实现。
系统调用的分类
进程控制 :创建进程、终止进程、进程通信等
文件操作 :创建文件、打开文件、读文件、写文件等
设备操作 :请求设备、释放设备、读写设备等
信息维护 :获取系统时间、设置系统时间等
通信 :创建管道、创建套接字等
系统调用的实现
用户程序通过陷入指令(Trap)进入内核态
内核执行相应的系统调用处理函数
处理完成后返回用户态,将结果返回给用户程序
操作系统面试题 1. 什么是操作系统?它的主要功能是什么? 操作系统是管理计算机硬件与软件资源的计算机程序,是计算机系统的核心与基石。它的主要功能包括进程管理、内存管理、文件系统、设备管理和用户接口。
2. 进程和线程的区别是什么?
资源分配:进程是资源分配的基本单位,线程共享进程的资源
调度:线程是 CPU 调度的基本单位
并发性:一个进程内的多个线程可以并发执行
系统开销:创建和切换线程的开销比进程小
3. 什么是死锁?产生死锁的必要条件是什么? 死锁是指多个进程因竞争资源而造成的一种僵局,若无外力作用,这些进程都将无法继续执行。产生死锁的必要条件包括:
互斥条件:资源不能被共享
请求和保持条件:进程已获得的资源在未使用完之前不能被剥夺
不剥夺条件:进程已获得的资源在未使用完之前不能被剥夺
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
4. 如何预防和避免死锁?
预防死锁 :破坏产生死锁的四个必要条件之一
避免死锁 :在资源分配时进行安全性检查,确保系统处于安全状态
检测和解除死锁 :允许死锁发生,然后检测并解除
5. 什么是虚拟内存?它的作用是什么? 虚拟内存是指操作系统为进程提供的一个比实际物理内存大得多的虚拟地址空间。它的作用是:
6. 分页和分段的区别是什么?
分页 :将物理内存划分为大小相等的页框,将进程的逻辑地址空间划分为大小相等的页
分段 :将进程的逻辑地址空间划分为若干个段,每个段对应一个逻辑单位
目的 :分页主要是为了提高内存利用率,分段主要是为了满足用户的需求
大小 :页的大小固定,段的大小不固定
地址空间 :分页的地址空间是一维的,分段的地址空间是二维的
7. 常见的进程调度算法有哪些?
先来先服务(FCFS)
最短作业优先(SJF)
最短剩余时间优先(SRTF)
优先级调度
时间片轮转(RR)
多级反馈队列调度
8. 常见的页面置换算法有哪些?
最佳置换算法(OPT)
先进先出置换算法(FIFO)
最近最久未使用置换算法(LRU)
时钟置换算法(Clock)
最不常用置换算法(LFU)
参考资料
《操作系统概念》(第九版),Abraham Silberschatz 等著
《现代操作系统》(第四版),Andrew S. Tanenbaum 著
《深入理解计算机系统》(第三版),Randal E. Bryant 等著
《Linux 内核设计与实现》(第三版),Robert Love 著
总结 操作系统是计算机系统的核心软件,负责管理和协调计算机的所有资源。本文从操作系统概述入手,详细介绍了进程管理、内存管理、文件系统、设备管理和用户接口等核心内容,并通过示例代码演示了一些重要的概念和算法。同时,本文还解答了一些常见的操作系统面试题,帮助读者更好地理解和应用操作系统知识。
学习操作系统不仅可以帮助我们理解计算机系统的工作原理,还可以提高我们的程序设计能力和系统调优能力。希望本文能够为读者提供一个全面、系统的操作系统学习总结,为进一步深入学习操作系统打下坚实的基础。