首页 > 其他分享 >操作系统学习01

操作系统学习01

时间:2023-08-16 21:15:16浏览次数:36  
标签:文件 01 操作系统 学习 调用 内存 Linux 共享 环境变量

UNIX系统简介:
1970年于美国的贝尔实验室,作者肯·汤普逊和丹尼斯·里奇
UNIX是最早的多用户、多任务、支持多种CPU架构。高稳定性、高可靠性、高安全性
既能构建大型关键型业务系统的服务器(银行、电信公司等),也能支持移动嵌入式设备

Minix是一种开源的基于微内核架构的类UNIX计算机操作系统,1987年发布,Linux之父林纳斯·托瓦兹受到Minix的启发,开发了Linux内核的第一个版本

Linux系统简介:
Linux:全称GNU/Linux,于1991年发布,它主要受到Minix和Unix思想的启发,是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。
它支持32位和64位硬件,能运行主要的Unix工具软件、应用程序和网络协议。
Linux继承Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统,Linux有上百种不同的发行版本

相关知识:
Linux的标志:企鹅,因为企鹅是在南极洲的标志动物,而南极目前没有被任何国家占有,属于全人类
GNU计划、组织:目前全球最大的开发开源系统的开源组织,负责Linux内核源的升级和维护
GPL通用许可证:在带有GPL证书的代码基础下开发出来的软件,也都需要支持GPL证书
POSIX:统一可移植操作系统接口:Linux是完全遵循的,UNIX绝大部份遵循,所以它们的命令、API接口基本上都是通用的
发行版:Linux只是内核,内核+Shell+基础软件 = 用户操作系统
    不同的公司可以根据Linux内核制作出不同版本、不同风格Linux发行版,例如:Ubuntu、Redhat、CentOS、Debian

GNU编译工具gcc\g++:
多样化:
支持多种编程语言、支持各种操作系统
gcc -v 查看版本信息
编译构建过程:
预处理:gcc -E code.c -o code.i
编译:gcc -S code.i 生成code.s汇编文件
汇编:gcc -c code.s 生成code.o目标文件
链接 gcc a.o b.o c.o 生成a.out可执行文件

编译参数:
-E 只显示预处理的结果
-S 只生成汇编文件
-c 只编译不链接
-o 指定编译结果的名字
-I 指定头文件的加载路径 -I path
-l 指定要使用的代码库 -lm导入数学库
-Wall 尽可能多地产生警告信息
-Werror 把警告当错误处理
-std 设置编译语法标准 -std=gnu89/99
-g 生成调试信息
-L 指定库文件的查找路径
-l 指定要加载的库文件名字 例如:-lm
-I 指定头文件的加载路径
-pedanic -anis 对于不符合ANIS/ISO标准的语法产生警告
预处理指令:
#include <>/"" 导入头文件
#define 定义宏常量、函数(宏名建议全部大写)
#undef 删除宏
#ifdef 宏存在则条件为真
#ifndef 宏不存在则条件为真
#endif

#if/#elif/#else/#endif  条件判断编译
#error  提示错误,并阻止生成可执行文件,一般与条件判断配合
    格式为:#error "提示信息"
#warning 提示警告
#line 设置行号 影响了提示信息、提示警告的行号
#pragma pack(n)设置对齐、补齐的最大子节数
#pragma once 相当于头文件卫士,防止头文件重复导入
#pragma GCC dependency “file.h” 监控文件是否有修改
#pragma GCC poison key 设置关键字key为毒药,禁止在后续代码中使用

库:
库文件是目标文件的集合,可以被其他代码调用,把代码封装成库文件后方便使用、方便管理,安全性高、保密性强

静态库:(xxx.a)
    就是目标文件的集合,当调用静态库时,编译器会把静态库的所有的二进制指令拷贝到最后的可执行文件中
    优点:运行速度要比共享库要快,运行时不需要依赖静态库文件
    缺点:可执行文件相对较大,当静态库有修改后,所有使用了该静态库的可执行文件都需要重新编译

共享库:(xxx.so)
    就是带入口的可执行文件,当调用共享库时,调用语句处会记录该函数在共享库中的位置,并且共享库文件要与运行的可执行文件一起
    加载到内存中,当执行到调用共享库代码的语句时,就会跳转到共享库二进制指令的内存中执行,执行完后会跳转回调用语句处
    优点:可执行文件相对较小。当共享库有修改,可执行文件不需要重新编译
    缺点:运行速度比静态库慢一些,运行时需要依赖与共享库文件

静态库:
制作静态库:
1、编译出目标文件
gcc -c xxx.c ...
2、打包目标文件生成静态库文件
ar -r libxxx.a 后面跟上想要放入的目标文件x.o....

使用静态库:
    1、直接使用:
        gcc xxx.c libxxx.a
    2、指定库文件的位置
        gcc xxx.c -Lpath -lxxx
            -L指定库的路径 -l库名 指定要加载的库(库名不包括前缀lib 后缀.a .so);
    3、通过修改配置文件中的环境变量来指定库的查找路径
     打开系统配置文件:
        vim ~/.bashrc
    在配置文件末尾添加:
        export LIBRARY_PAT=$LIBRARY_PATH:新路径(绝对路径)
    保存退出并重新加载配置文件
        source ~/.bashrc
    使用静态库:
        gcc xxx.c -lxxx

共享库:
制作共享库:
1、编译生成目标文件
gcc -fpic -c xxx.c
-fpic 生成与位置无关的文件
2、生成共享库文件
gcc -shared -fpic a.o b.o c.o... -o libxxx.so

使用共享库:
    1、直接使用:
        gcc xxx.c libxxx.so
    2、指定库文件的位置
        gcc xxx.c -Lpath -lxxx
            -L指定库的路径 -l库名 指定要加载的库(库名不包括前缀lib 后缀.a .so);
    3、通过修改配置文件中的环境变量来指定库的查找路径
     打开系统配置文件:
        vim ~/.bashrc
    在配置文件末尾添加:
        export LIBRARY_PAT=$LIBRARY_PATH:共享库路径
    保存退出并重新加载配置文件
        source ~/.bashrc
    使用共享库:
        gcc xxx.c -lxxx
运行时:
    运行时,系统会去默认指定的共享库加载路径进行加载共享库,一般通过修改配置文件的环境变量进行设置
    export LD_LIBRARY_PAT=$LD_LIBRARY_PATH:共享库的加载路径

注意:
1、如果指定路径下有同名的静态库文件、共享库文件,gcc编译器会默认优先加载共享库
2、如果想要优先使用同名静态库文件 增加 -static 编译参数实现
3、对配置文件中的环境变量进行删除修改时,最好重启终端才生效

动态使用共享库:
作用:在代码中决定使用哪些共享库,编译时不需要指定,执行时还是需要依赖共享库

库文件相关辅助命令:
ldd 查看可执行文件依赖哪些共享库 ldd ./a.out
nm 查看目标文件、可执行文件、静态库、共享库文件的符号列表
strip 减肥 删除目标文件、可执行文件、静态库、共享库文件的符号列表

环境变量表:
操作系统会给每个执行的程序提供一张环境变量表,该表中记录了操作系统在提供的时候所处于的所有环境变量,这些环境变量反映了操作系统的配置情况以及该程序所处操作
系统中的环境情况

通过声明 extern char** environ;就可以使用该程序的环境变量表,这个表可以随意使用,因为这个表只是操作系统提供的一张拷贝表而已
for(int i=0; environ && environ[i];i++)
 {
    printf("%s\n",environ[i]);  //依靠遍历来打印出来
 }

操作环境变量表的函数:
char *getenv(const char *name);
功能:通过环境变量名获取它的值

int setenv(const char *name, const char *value, int overwrite);
功能:向环境变量表中添加新的环境变量
name:环境变量名
value:环境变量的值
overwrite:当环境变量存在时
非0 修改原来环境变量的值
0 不修改
返回值:成功返回0,失败返回-1

int unsetenv(const char *name);
功能:删除环境变量
返回值:成功返回0,失败返回-1

int clearenv(void);
功能:清空环境变量表

int putenv(char* string)
功能:向环境变量表中添加新的环境变量或修改值
string:以 环境变量名=环境变量值

错误处理:
1、通过函数返回值表示出现错误
a、合法值表示成功、非法值表示失败
例如:查找位置、计算大小等
b、返回值是指针类型时,返回NULL或者0xFFFFFFFF表示失败,其余都表示成功
malloc\mmap
c、返回0表示成功,-1表示失败,一般都是操作系统函数
d、永远成功 例如:printf
2、通过改变全局的错误编码,来表示出现了错误
errno 定义在errno.h中
由于系统函数执行导致出现错误,就会改变errno的值
char *strerror(int errnum);
功能:根据errno的值获取对应的错误信息
注意:errno是一个全局变量,所以不能只根据它的值是否为0就简单的判断是否是产生错误
一、内存管理
用户层
STL 智能指针/容器 自动分配、释放 调用C++
C++ new/delete 调用C
C malloc/free 调用POSIX\Linux
POSIX brk/sbrk 调用内核
Linux mmap/munmap 调用内核

系统层
Kernal  kmalloc/vmalloc                 调用驱动
dirver  get_free_page

二、进程映像
程序:存储在磁盘上的可执行文件(二进制、脚本),当执行程序时,系统会把可执行文件加载到内存形成进程,
一个程序可以同时加载出多个进程
进程在内存中的分布情况就是进程映像,从低地址到高地址依次是:
text 代码段: 二进制指令、常量(数值、“字符串字面值”、被const修饰过的原data的数据),只读,强制修改会段错误
data 数据段: 初始化过的全局变量、初始化过的静态局部变量
bss 静态数据段: 未初始化过的全局变量、未初始化过的静态局部变量程序运行前自动清0;
heap 堆: 程序员手动管理的大量数据,管理麻烦、申请和释放的受控,与指针配合使用,使用不当可能会内存泄露、内存碎片
stack 栈: 局部变量、块变量,大小有限、自动申请、自动释放、不可能存在内存碎片
environ 环境变量表:所有的环境变量,每个进程都有一份,修改不会影响系统真正的环境变量的值
argv 命令行参数:程序执行时附带的参数

练习:打印出各个内存段段数据的地址,与该进程的maps文件中记录的内存分布比较
查看maps:/proc/进程ID/maps
查看进程ID:
命令:ps -aux 函数:getpid()

三、虚拟内存
1、32位系统会给每个进程分配4G的虚拟内存空间(所谓的32位系统有两种解释:一是对cpu32位管脚可以识别,二是操作系统的位数)
2、进程、用户只能使用访问虚拟内存,无法直接使用真实的物理内存
3、虚拟内存只有与物理内存进行映射(也就是建立一对一的关系)后才能使用,否则会产生段错误
4、虚拟内存与物理内存的映射和对应使用都是由操作系统动态维护
5、虚拟内存技术一方面是为了让系统更加安全,可以不暴露真实的物理内存地址给用户,又可以让一个进程出错后不影响其他进程
和系统的运行,另一个方面可让进程使用比实际物理内存更大的空间
6、4G的虚拟内存地址分成两部分
[0~3G)(不包括3G) 用户空间
[3G~4G) (不包括4G) 内核空间
7、当进程\线程运行在内核空间时,称该进程\线程处于内核态,当进程\线程运行在用户空间时,称该进程\线程处于用户态
8、在内核态下,进程运行在内核空间,此时CPU可以执行任何指令,此时运行的代码不受任何的限制,可以自由访问任何有效的地址
9、在用户态下,进程运行在用户空间,此时进程不能直接访问内核空间的数据,此时可以通过系统调用(API 系统接口函数)的方式来切换到内核态
间接的访问内核空间的数据
10、对虚拟内存越界访问(访问没有映射过的虚拟内存),导致段错误

四、映射虚拟内存和物理内存的函数
sbrk/brk/mmap/munmap
关于malloc获取虚拟内存实际调用POSIX、Linux提供的函数受到操作系统、编译器、字节数的影响,大致的逻辑:
1、如果申请小于128kb调用sbrk\brk
2、如果申请大于128kb调用mmap\munmap
注意:strace ./a.out 可以追踪到程序的底层调用(用户层)

注意:系统内存映射是以页(1页=4096字节)为单位的

注意:sbrk、brk底层维护一个映射位置指针,该指针指向虚拟内存中映射过的内存的最后一个字节的下一个位置,可以通过移动该指针
来实现映射内存和取消映射的效果

void *sbrk(intptr_t increment);
功能:通过增量increment来调整映射位置指针的位置,从而进行映射或取消映射
    increment:增量(字节为单位)
        0  获取映射位置指针的位置
        >0 映射内存
        <0 取消映射
返回值:映射指针原来的位置

int brk(void *addr);
功能:通过修改映射指针指向addr的地址,从而进行映射或取消映射
    addr:
        >原来的位置 映射
        <原来的位置 取消映射
返回值:成功返回0 失败返回-1

总结:sbrk、brk都属于POSIX标准中的内存映射函数,都是可以单独进行映射、取消映射,但是配合使用最方便(sbrk映射、brk映射)

   void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
   功能:映射虚拟内存与物理内存
        addr:映射内存的起始地址,可以自己指定,如果赋NULL则由操作系统指定
        length:要映射的字节数
        prot:映射后的权限
            PROT_EXEC     执行权限  PROT_EXEC|PROT_READ (这样即有执行权限也有读权限)
            PROT_READ     读权限
            PROT_WRITE    写权限
            PROT_NONE     没有权限
        flags:映射标志
            MAP_FIXED   如果提供的addr无法映射,则直接失败
            MAP_ANONYMOUS   指定映射虚拟内存,不映射文件,fd、offset失效
            MAP_SHARED  对映射后的内存可以共享给其他进程
            MAP_PRIVATE 对映射后的内存只能当前进程使用
                注意:flags中必须在MAP_SHARED、MAP_PRIVATE之间二选一
        fd:文件描述符 可以让文件映射到物理内存,不需要映射文件直接写0
        offset:文件的偏移位置,从该位置开始映射文件
    返回值:成功的话返回映射后的内存首地址,失败返回(void*)-1


   int munmap(void *addr, size_t length);
   功能:取消映射
        addr:映射的内存首地址
        length:取消映射的字节数
        返回值:成功返回0,失败返回-1

五、Linux内存管理的总结
1、mmap\munmap底层不维护任何东西,直接在堆内存中选择合适的内存进行映射,返回映射成功后的内存首地址
2、sbrk\brk底层维护一个映射位置指针,该指针记录了通过sbrk\brk映射内存的末尾位置,通过改变该指针的位置来映射和取消映射
3、malloc\free底层调用了sbrk\brk 或者 mmap\munmap,虚拟内存必须与物理内存建立映射关系后才能使用
4、每个进程都有4G(32位)的虚拟内存空间
5、内存管理的重点是理解Linux对内存管理机制,而不是sbrk\brk\mmap\munmap函数的使用

六、系统调用(系统API、系统函数)
系统调用指的是由操作系统提供的一些功能给程序员调用,这些功能已经被封装成c语言函数的形式,但它们不属于标准c的一部分,也不是
真正的函数
一般的应用进程工作运行在用户态(0~3G),使用系统调用时进程会转入内核态(3~4G)
常用的c标准库函数的大部分时间都工作在用户态,当底层进行系统调用时会偶尔转入内核态工作

通过time命令查看进程在两种状态下的运行时间情况

    real	0m0.667s    总的执行时间
    user	0m0.311s    用户态执行时间
    sys	    0m0.263s    内核态执行时间
系统调用的代码是内核的一部分,其外部接口以c函数的形式存储在共享库中(/lib64/ld-linux-x86-64.so.2,/lib64/ld-linux-x86-64.so.2),
当调用这些外部接口时进程会以软中断的方式进入内核态执行真正的系统调用函数

七、一切皆文件
Linux/UNIX操作系统把所有的服务、设备、协议都抽象成文件的形式,提供了一套统一而简单的文件IO的系统调用,简称系统的文件IO
也就是说在Linux和UNIX中任何对象都可以被当作是某种特殊的文件,都可以像访问文件一样,访问这些对象

文件分类;
    普通文件    -   包括纯文本文件、二进制文件、各种压缩文件
    目录文件    d   必须有执行权限才能进入目录
    块设备文件  b   保存大块数据的硬件设备,例如磁盘   
    字符设备文件 c  操作字符相关的设备 例如键盘、鼠标等
    socket文件(套接字文件)   s 通常用于网络通信
    管道文件    p   用于进程间通信
    链接文件    l   类似windows的快捷方式

八、文件相关的系统调用

int open(const char *pathname, int flags);
功能:打开文件
    pathname:文件的文件
    flags:打开文件的方式
        O_RDONLY    只读
        O_WRONLY    只写
        O_RDWR      读写
        O_APPEND    追加
        O_CREAT     文件不存在则创建
        O_EXCL      配合O_CREAT,如果文件存在则失败
        O_TRUNC     文件如果存在,则清空打开
返回值:成功返回的是文件描述符,类似于FILE*,代表一个打开的文件(>=0),负数表示失败
int open(const char *pathname, int flags, mode_t mode);
功能:打开或者创建文件(文件不存在)
    flags:O_CREAT
mode:
    S_IRWXU  00700 拥有者 读写执行权限
    S_IRUSR  00400        读权限
    S_IWUSR  00200        写权限
    S_IXUSR  00100        执行权限
    S_IRWXG  00070 同组用户 读写执行权限
    S_IRGRP  00040         读
    S_IWGRP  00020          写
    S_IXGRP  00010          执行
    S_IRWXO  00007 其它用户 读写执行权限
    S_IROTH  00004          读
    S_IWOTH  00002          写
    S_IXOTH  00001          执行
    注意:可给宏名 也可以给 权限掩码 (0xxx) 八进制
    读权限(r):对应数值为 4。
    写权限(w):对应数值为 2。
    执行权限(x):对应数值为 1。
    例如:对于八进制0644,表示拥有者的权限是读和写,其他用户和同组用户的权限是读,也就是-rw-r--r--


int creat(const char *pathname, mode_t mode);
功能:创建文件
mode:同上

ssize_t write(int fd, const void *buf, size_t count);
功能:把内存中的数据写入到文件中
fd:文件描述符  open creat的返回值
buf:待写入的内存的首地址
count:要写入的字节数
返回值:成功写入的字节数,失败返回-1

ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据到内存中
fd:文件描述符  open creat的返回值
buf:要存储读取出来的数据的内存首地址
count:要读取的字节数
返回值:成功读取的字节数

标签:文件,01,操作系统,学习,调用,内存,Linux,共享,环境变量
From: https://www.cnblogs.com/c-learnmore/p/17636182.html

相关文章

  • games101-lecture-notes
    Games101课程笔记Created:2023-06-07T20:54+08:00Published:2023-08-16T21:05+08:00Categories:ComputerGraphics目录Lecture01:OverviewofComputerGraphicsmotivation:学了有什么用?课程内容课程资源Lecture02:ReviewofLinearAlgebra点乘叉乘叉乘的作用Lecture03......
  • 七月学习之Firewalld实现NAT
    6、Firewalld实现NAT6.1、DNAT应用场景基本概念:端口转发是指传统的目标地址映射,实现外网访问内网资源实现原理:firewalld使用的是代理方式来实现地址映射,会占用随机端口实现语法:firewall-cmd--permanent--zone=<区域>--add-forward-port=port=<源端口号>:proto=<协议>:toport=......
  • [usaco2018 jan] sprinklers
    题目农夫约翰有一块很大的田,他正在考虑种甜玉米。经过对他农田的调查,FJ发现它形成了一个(N-1)×(N-1)的正方形。西南角为坐标(0,0),东北角是(N-1,N-1)。在某些整数坐标的位置中有双头喷头,每一个都能够同时喷洒水和肥料。一个在(i,j)处的双头喷头会将水洒在农田中所有在其东面且在其北面的区......
  • 01
    awwa 1#include<bits/stdc++.h>2#definelllonglong3usingnamespacestd;4constintN=40,M=300000;5intn,mod,a[N],ans;6intp1[M],p2[M],idx1,idx2;78voiddfs1(intp,intsum)9{10if(p==n/2+1)11{......
  • 「学习笔记」指针的基础入门
    为啥会突然学这个呢?因为长链剖分优化DP的状态转移用到了指针数组,平时的STL使用中也经常碰到指针。So,就去学了一下,记录一下学习的笔记。我绝对不会告诉你另一个原因是因为最近做DP做累了想来写篇博文水水时间引入我们平时用scanf输入的时候,都会在变量名前加一个&,但是,字......
  • 网络编程day01--socket套接字
    进程间通信-socket套接字基本特征:socket是一种接口技术,被抽象了一种文件操作,可以让同一计算机中的不同进程之间通信,也可以让不同计算机中的进程之间通信(网络通信)本地进程间通信编程模型:进程A                                        ......
  • SQL:DAC模式登陆SQL SERVER 2012 批量执行SQL 脚本文件
    rem将当前目录下的所有*.SQL文件执行一次,并将结果输出文件remfor循环执行SQL命令文件echo=======Begin===========for%%iin(*.sql)do(sqlcmd-A-SLOCALHOST-USA-Pyourpassword-iD:\SQL\IN\%%i-oD:\SQL\OUT\%%i@echoFileName%%i)echo=======end......
  • P3017 [USACO11MAR] Brownie Slicing G
    P3017[USACO11MAR]BrownieSlicingG[P3017USACO11MAR]BrownieSlicingG-洛谷|计算机科学教育新生态(luogu.com.cn)目录P3017[USACO11MAR]BrownieSlicingG题面翻译题目描述输入格式输出格式样例#1样例输入#1样例输出#1思路code题面翻译Bessie烘焙了一块巧克......
  • 【深度挖掘Java并发编程底层源码】「底层技术原理体系」带你零基础认识和分析学习相关
    FutureTask的基本介绍FutureTask是Java中的一个类,它实现了Future接口和Runnable接口,并且被用作线程执行的任务。FutureTask可以在多线程环境下异步执行一个任务并获取其结果。FutureTask的特点用法异步执行:通过将耗时的任务交给FutureTask,在一个单独的线程中执行,当前线程可以继续执......
  • 学习笔记 - Java 面向对象_上
    学习面向对象内容的三条主线Java类及类的成员:属性、方法、构造器;代码块、内部类面向对象的特征:封装、继承、多态、(抽象)其他关键字的使用:this、super、package、import、static、final、interface等类的相关概念类和对象概述类(Class)和对象(Object)是面向对象的核心概念。......