负责进程的创建、调度、同步、通信和销毁
- **进程创建:**当用户或应用程序请求创建新进程时,操作系统会分配新的PCB(Process Control Block,进程控制块),记录进程的基本信息
- 如进程标识符PID、进程状态、优先级、程序计数器、内存映射表等
- **进程调度:**操作系统维护一个就绪队列,其中包含了所有可以执行的进程
- 调度器根据某种调度算法,选择一个进程投入执行
- 先来先服务
- 调度器根据某种调度算法,选择一个进程投入执行
包括进程控制块(PCB)管理、进程调度算法、进程间通信机制等。
整体以数据结构的形式存在于操作系统的内核内存中。
- 内核内存:操作系统内核使用的内存区域,包括内核代码、内核数据结构、硬件驱动程序等
- 这部分内存是受保护的
- 通常位于内存空间的特定区域,对用户态进程不可见,也不可直接访问
负责内存的分配、回收、映射和保护
包括内存分区、分页管理、虚拟内存、内存分配表(页表、段表)等
响应硬件中断和软件异常
提供中断描述符表(IDT)或类似的结构,以及中断服务例程(ISR)和异常处理程序
管理和控制各类硬件设备
提供设备驱动框架,以及设备控制器的初始化、I/O请求的提交和完成
提供供用户程序调用的系统调用接口,使用户程序能够请求内核服务
如文件操作、进程控制、定时器设置等
-
进程控制
- 创建进程
fork()
、clone()
:创建新进程副本 - 终止进程
exit()
:结束当前进程并清理资源 - 进程调度
sleep()
、yield()
:控制进程的执行状态 - 进程间通信与同步
wait()
、signal()
、pipe()
、semaphore
:实现进程间的消息传递和同步
- 创建进程
-
内存管理
-
分配和释放内存
malloc()
、calloc()
、realooc()
、free()
:在用户态通常由C库封装,底层可能通过系统调用实现-
malloc()
用于在程序运行时动态地从内存堆中分配一块连续的、指定大小的内存区域。分配的内存区域在分配时未初始化,其内容是不确定的-
void* malloc(size_t size);
-
size
指定要分配的字节数 -
函数返回一个指向所分配内存区域的指针,若分配失败则返回
NULL
-
malloc()
与new
的区别:malloc()
是C语言中的函数,仅仅分配内存,不执行构造函数或析构函数,分配失败不会抛出异常,而是返回NULL
- C++中的
new
关键字除了分配内存外,对于类类型对象还会调用构造函数初始化对象,分配失败会抛出std::bad_alloc
异常。new
操作符分配的内存可以通过delete
操作符释放,且delete
会调用析构函数- 先分配内存,再在内存上调用构造函数初始化对象
-
-
calloc()
不仅分配内存,还会对分配的内存区域进行初始化,将其所有字节置零void* calloc(size_t num, size_t size);
num
指定元素个数size
指定每一个元素的大小- 函数返回一个指向所分配内存区域的指针,若分配失败则返回
NULL
-
realloc()
用于改变已经分配的内存区域的大小。- 可以增大或减少原有内存块的大小,也可以移动内存块到另一个位置以适应新的大小
void* realloc(void* ptr, size_t new_size);
ptr
指向之前分配的内存区域new_size
是新的字节数- 若成功,返回新分配的内存区域的指针(可能与原地址相同也可能不同)
- 若分配失败或者
ptr
为NULL
,则返回NULL
而不改变原有的内存块
-
free()
用于释放上述函数动态分配的内存空间,以防止内存泄漏void free(void* ptr);
- 参数
ptr
是指向要释放的内存区域的指针。一旦释放,该指针应设为NULL
以防误用。
-
-
映射和解除映射内存
mmap()
、munmap()
:控制虚拟内存区域-
详见内存映射
-
mmap()
是POSIX系统调用,用于将文件或匿名内存区域映射到进程的地址空间中,从而可以直接通过内存访问文件内容或者创建大块的匿名内存void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
addr
:期望映射到的地址,通常设置为NULL
让系统自动选择地址length
:映射区域的大小prot
:内存区域的保护标志,如可读、可写、可执行等flags
:控制映射的选项,如是否持久化、是否共享、是否匿名等fd
:要映射的文件描述符,如果是匿名映射,则传入-1
offset
:文件映射时相对于文件开始位置的偏移量
-
munmap()
:用于解除由mmap()
创建的内存映射关系,使得映射区域不再与文件或者匿名内存关联,释放这块内存资源int munmap(void* addr, size_t length);
addr
:指向映射区域的起始地址length
:要解除映射的内存区域的大小,必须与mmap()
时一致
-
-
-
文件系统操作
- 打开、关闭文件
open()
、close()
:管理文件句柄 - 读写文件
read()
、write()
:进行文件内容的读写操作 - 文件查找、创建、删除、重命名
stat()
、fopen()
、unlink()
、rename()
:管理文件和目录
- 打开、关闭文件
-
设备管理
- 控制设备
确保不同用户和进程只能在权限许可范围内操作
实现身份验证、访问控制、审计等功能
- 硬件自检
- 进程是操作系统资源分配的基本单位,每个进程都有自己的虚拟内存空间
- 虚拟内存空间包括代码段、数据段、堆和栈
- 进程各自独立运行,彼此互不影响
- 进程之间需要通过进程间通信(IPC)机制进行数据交换
- 线程是操作系统调度的基本单位,一个进程可以有一个或多个线程
- 同一进程内的所有线程共享相同的虚拟内存空间
- 包括全局变量和打开的文件等资源
- 但每个线程有自己的程序计数器、寄存器集合和栈
- 线程间的通信相对简单且快速,因为它们位于同一个内存空间
- 同一进程内的所有线程共享相同的虚拟内存空间
内核态(Kernel Mode):操作系统内核在内核态下运行,可以直接访问和控制计算机硬件资源
- 如处理器、内存、I/O设备等
内核态下执行的代码可以执行所有的机器指令,不受任何限制
- 包括对内存的任意访问、中断处理、系统调用服务、硬件资源管理等
用户态(User Mode):应用程序
在C语言中,volatile
关键字是一个类型修饰符,指出变量的值可能会在程序的控制或是硬件的作用下发生变化,因此编译器每次使用这个变量的时倩都要从它的地址中读取这个变量的值,而不是使用寄存器中的备份。
volatile关键字的主要作用如下:
-
防止编译器优化:编译器通常会对代码进行优化,其中包括假设局部变量或全局变量在没有显示赋值的地方其值不变。然而,对于标记为
volatile
的变量,编译器会放弃这种优化,确保每次对这类变量的读写操作都会实际访问内存。这意味着每次引用该变量时,都会直接从内存中读取其最新的值,而不是使用寄存器或其他优化方式存储的旧副本。 -
确保多线程间的可见性:尽管C语言标准并没有明确规定
volatile
关键字能够提供多线程环境下的原子性和同步机制,但在多线程编程中,如果多个线程同时访问一个volatile
变量,至少可以保证当一个线程改变了该变量的值时,其他线程能够看到这个新的值。但这并不意味着volatile
能替代锁或其他同步原语来实现复杂的并发控制;在涉及多线程共享数据时,还需要使用互斥锁或其他同步手段来保证数据的一致性。 -
适用于硬件交互:在嵌入式系统和实时操作系统编程中,
volatile
经常用于声明那些会被硬件中断或DMA操作更改的内存位置,比如设备寄存器。声明为volatile
的变量会迫使编译器生成对应的读写内存操作,确保与硬件通信的有效性。
综上所述,volatile
关键字主要用于提示编译器不应对变量进行不必要的优化,并且在多线程或多处理器环境下强调变量值可能会发生意料之外的变化。但它不能取代专门的内存屏障、原子操作或者锁机制来保证复杂同步场景的安全性。