一、使用文件IO进行相关练习
1.使用文件IO完成,将源文件中的所有内容进行加密(大写转小写、小写转大写)后写入目标文件中
1.1> pwd.c
#include <myhead.h>
//字符串大小写转写函数
int letter_transcription(char *buf, int len)
{
for(int i=0; i<len; i++)
{
if(buf[i]>='A' && buf[i]<='Z')
{
buf[i]+=32;
}
else if(buf[i]>='a' && buf[i]<='z')
{
buf[i]-=32;
}
}
return len;
}
int main(int argc, const char *argv[])
{
//判断传入文件个数
if(argc !=3 )
{
write(2, "input file error\n", sizeof("input file error\n"));
return -1;
}
//定义文件标识符
int sfd, //源文件
dfd; //目标文件
//以只读的形式打开源文件
if((sfd = open(argv[1], O_RDONLY)) == -1)
{
perror("sdf open error");
return -1;
}
//以只写形式打开目标文件
if((dfd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0664)) == -1)
{
perror("dfd open error");
return -1;
}
//定义文件搬运工
char buf[128] = "";
int res = 0; //实际读取的文件个数
//加密逻辑
while((res=read(sfd, buf, sizeof(buf))) != 0) //读取源文件内容
{
write(dfd, buf, letter_transcription(buf, res)); //源文件内容加密,同时将加密内容写入目标文件
}
//关闭文件
close(sfd);
close(dfd);
return 0;
}
1.2> 程序执行效果
二、其他相关概念
1.并发和并行的区别
1.1> 并发(Concurrency)
- 并发指的是多个任务在宏观上同时进行,但在微观上是交替执行的。
- 并发涉及到任务的调度,操作系统通过时间分片来让多个任务看似同时进行。
- 并发不一定需要多核处理器,单核处理器上也可以实现并发,通过操作系统的调度算法来实现。
- 并发的目的是提高资源的利用率和系统的整体性能。
1.2>并行(Parallelism)
- 并行指的是多个任务或计算在物理上同时进行。
- 并行需要多个处理器或核心,每个处理器或核心可以独立执行任务或计算。
- 并行可以是数据并行,即多个处理器同时处理不同的数据;也可以是任务并行,即多个处理器同时执行不同的任务。
- 并行的目的是提高计算速度,通过同时执行多个操作来减少总体的执行时间。
简而言之,并发强调的是任务的管理和调度,而并行强调的是物理上同时执行多个任务的能力。并发可以在单个处理器上实现,而并行则需要多个处理器或核心。
2.什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
进程的概念主要有两点:第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
3.进程和程序的区别
进程和程序是两个不同的概念,它们在计算机科学中扮演着不同的角色:
3.1> 程序(Program)
- 程序是一组指令的集合,它们被编写来完成特定的任务或功能。
- 程序通常存储在磁盘或其他存储介质上,它们是静态的,直到被加载到内存中。
- 程序本身不包含状态信息,它只是一个可执行的代码集合。
3.2> 进程(Process)
- 进程是程序的执行实例。当程序被执行时,操作系统会为其创建一个进程。
- 进程是动态的,它包括程序代码、程序计数器、寄存器、堆栈、数据段等。
- 进程拥有自己的内存空间,并且可以独立于其他进程运行。
- 进程可以被操作系统调度执行,可以处于就绪、运行或阻塞等状态。
以下是进程和程序之间的一些关键区别:
- 存储位置:程序通常存储在磁盘上,而进程存在于内存中。
- 动态性:程序是静态的代码集合,进程是动态的执行实例。
- 独立性:每个进程都有自己独立的内存空间和系统资源,而程序本身不包含这些。
- 状态信息:进程包含状态信息,如寄存器值、程序计数器等,而程序不包含。
- 并发性:多个进程可以并发执行,而程序本身不能并发,除非它们被加载到不同的进程中。
- 生命周期:进程有生命周期,它们可以被创建、执行、暂停、终止等,程序本身没有生命周期,直到被加载到进程中。
- 执行环境:进程提供了程序执行所需的环境,包括操作系统资源和执行状态。
简而言之,程序是一组指令,而进程是程序在执行时的实体,包含了程序代码、数据和状态信息。
4.进程的状态有哪些
进程在其生命周期中会经历几种不同的状态,这些状态反映了进程与CPU的关系以及它们在执行过程中的不同阶段。以下是一些常见的进程状态:
4.1> 新建(New or Initialization)
- 进程被创建时的状态,操作系统正在为进程分配资源,如内存、文件描述符等。
4.2> 就绪(Ready)
- 进程已经准备好执行,等待操作系统调度分配CPU时间。进程处于就绪状态时,它已经具备了执行所需的所有资源。
4.3> 运行(Running)
- 进程当前正在执行。在单核系统中,一次只有一个进程可以处于运行状态;在多核系统中,可以有多个进程同时处于运行状态。
4.4> 阻塞(Blocked or Waiting)
- 进程正在等待某些事件发生,如I/O操作完成、信号量或锁的释放等。在这种状态下,进程不能执行,直到它等待的事件发生。
4.5> 终止(Terminated)
- 进程已经完成执行或被操作系统终止。在这种状态下,操作系统将释放进程占用的资源,并准备将进程的信息从系统中清除。
4.6> 挂起(Suspended or Stopped)
- 进程因为某些原因被暂停执行,可能是操作系统的调度决策,或者是用户通过系统调用请求挂起。挂起的进程可以被恢复到就绪或运行状态。
4.7> 僵尸(Zombie)
- 进程已经完成执行,但是其父进程还没有调用`wait()`或`waitpid()`系统调用来读取其退出状态。僵尸进程仍然保留在系统中,直到父进程读取其状态。
4.8> 睡眠(Sleeping)
- 进程主动进入睡眠状态,等待某个条件成立或者超时。在这种状态下,进程不会消耗CPU资源。
这些状态可以通过操作系统的进程管理机制进行转换,如进程调度算法、中断处理、系统调用等。不同的操作系统可能使用不同的术语或状态模型,但上述状态是大多数操作系统中常见的。
5.系统中的多个进程的调度机制都有哪些
5.1> 先来先服务(FCFS, First-Come, First-Served)
- 这是最简单的调度算法,按照进程到达的顺序进行调度。
5.2> 短作业优先(SJF, Shortest Job First)
- 优先调度估计执行时间最短的进程,可以减少平均等待时间。
5.3> 最短剩余时间优先(SRTF, Shortest Remaining Time First)
- 从当前运行的进程和就绪队列中选择剩余时间最短的进程。
5.4> 优先级调度(Priority Scheduling)
- 每个进程被赋予一个优先级,优先级最高的进程先执行。
5.5> 时间片轮转(RR, Round Robin)
- 每个进程被分配一个固定的时间片,所有进程轮流执行它们的时间片。
5.6> 多级队列(MLQ, Multi-Level Queue)
- 将进程分配到不同的队列中,每个队列有自己的调度算法。
5.7> 多级反馈队列(MFQ, Multi-Level Feedback Queue)
- 结合了时间片轮转和优先级调度,允许进程在不同的优先级队列之间移动。
5.8> 基于公平的共享调度(FIFO, Fair Share Scheduling)
- 确保每个进程获得公平的CPU时间分配。
5.9> 实时调度(Real-Time Scheduling)
- 为满足实时任务的时限要求,通常分为硬实时和软实时调度。
5.10>完全公平调度(CFS, Completely Fair Scheduler)
- 现代操作系统(如Linux)使用的调度算法,旨在提供公平的CPU时间分配。
5.11>比例份额调度(Proportional Set Scheduling)
- 允许进程组根据其资源需求获得CPU时间的比例。
5.12>批次调度(Batch Scheduling)
- 将多个进程分批进行调度,以减少上下文切换的开销。
这些调度算法可以根据不同的系统需求和目标进行选择和实现。例如,一些系统可能需要优先处理交互式任务,而其他系统可能更关注长作业的吞吐量。操作系统设计者需要根据具体的应用场景和性能要求来选择最合适的调度策略。