静态库和共享库的区别优缺点
静态库:
就是目标文件的集合,调用静态库文件就是把静态库中的二进制指令拷贝到可执行文件中
code.c + math.a
优点:运行速度相对比共享库较快,可执行文件运行时不需要依赖静态库
缺点:可执行文件相对较大,当静态库修改后,可执行文件需要重新编译
共享库:
就是没入口的可执行文件的集合,调用共享库时就是记录共享库二进制的指针的位置即可,当执行可执行文件时共享库文件就会一起加载到内存中,可执行文件就可以跳转到共享库中运行
优点:可执行文件相对较小,当共享库修改后,可执行文件不需要重新编译
缺点:运行速度比静态库慢,可执行文件运行时也需要依赖共享库
如何制作静态库和共享库
静态库:
gcc -c code.c
ar -r libname.a a.o b.o …
共享库:
gcc -fpic -c code.c
gcc -shared -fpic a.o b.o c.o … -o libname.so
如何使用共享库和静态库
静态库:
直接使用 gcc code.c libname.a
指定库文件位置 gcc code.c -Lpath -lname.a
环境变量 export LIBRARY_PATH=$LIBRARY_PATH:path
共享库:
直接使用 gcc code.c libname.so
指定库文件路径 gcc code.c -Lpath
环境变量
Linux常用指令
cd ls ls-l ctrl+L pwd whoami touch cat/more/head/tail rm rmdir rm -rf cp mv mkdir
ifconfig sudo find grep sudo apt-get sudo init 0
sudo reboot chmod tar man
什么是虚拟内存:
1、系统会给每个进程分配4G(32位)虚拟内存空间
32个0 ~ 32个1 地址范围
2、用户只能使用虚拟内存地址,无法直接使用物理内存地址
3、虚拟地址与物理内存之间需要进行映射才能使用,否则就会产生段错误
4、虚拟地址与物理内存的映射由操作系统动态维护
5、让用户使用虚拟地址一方面为了安全,另一方面操作系统可以让应用程序使用比实际物理内存更大的地址空间
6、4G的虚拟地址分为两部分
[0~3G) 用户空间
[3~4G) 系统空间
7、用户空间中代码不能直接访问内核空间的代码和数据,可以通过系统调用和API来切换到内核态,简介地与内核交换数据
8、对虚拟内存越界访问(使用了没有映射的内存),将导致段错误
映射虚拟内存和物理内存的函数
系统调用:(系统调用API)
系统调用就是操作系统提供的一些功能供程序员调用,这些系统调用已经被封装成了C函数的形式,但它们不是标准C的一部分
一般应用程序运行在用户态(03G),使用系统调用时进入内核态进行系统调用(34G)
常用的标准库函数大部分时间都运行在用户态,底层偶尔也会调用系统调用,从而进入内核态 malloc
总运行时间 = 用户态时间 + 内核态时间 + 切换时间 + IO时间 + CPU时间
文件的分类:
文件类型 | 前缀 | |
---|---|---|
普通文件 | - | 包括纯文本文件、二进制文件、压缩文件 |
目录文件 | d | 文件夹 |
块设备文件 | b | 保存大块数据的设备,例如硬盘 |
字符设备文件 | c | 类似键盘、鼠标等 |
管道文件 | p | |
链接文件 | l | |
Socket文件 | s | 通常用于网络连接 |
信号阻塞
当程序执行一些特殊操作时不适合处理信号,此时可以让内核先屏蔽信号,等这些操作结束后再发送该信号
当信号产生时,内核会在其维护的信号表中为进程设置一个与信号对应的一个标记,该过程叫做递送
从信号产生到完成递送有个时间间隔,处在这个间隔的信号状态叫做未决
信号屏蔽就是让信号先处于未决状态,暂停递送,当屏蔽解除时继续递送
每个进程都有一个信号集,专门用来储存要被屏蔽的信号
进程的分类
交互进程、批处理进程、守护进程
查看进程
简单方式 ps 显示当前用户有控制终端的进程信息
列表方式 ps auxw 显示所有进程详细信息
a 所有用户的有控制终端的进程
x 无控制终端的进程
u 显示进程的详细信息
w 以更大的列宽显示
进程的状态
O 就绪,等待被调度
R 运行,Linux系统没有0,就绪也用R表示
S 可被唤醒的睡眠,例如系统中断、获得资源、收到信号都可以唤醒它进入运行态
D 不可唤醒的睡眠,只能被系统唤醒
T 暂停态 收到SIGSTOP信号进入暂停态,收到SIGCONT信号转入运行态
W 等待内存分页 (2.6内核后被废弃了)
Z 僵尸状态
X 死亡状态
< 高优先级
N 低优先级
l 多线程的进程
s 进程的领导者
L 有内存被锁进内存
+ 处于后台的进程组
START 进程启动的时间
TIME
COMMAND 启动进程的命令
父进程、子进程、孤儿进程与僵尸进程
一个进程可以被另一个进程创建,创建者叫父进程,被创建者叫做子进程,子进程被父进程启动后会在操作系统的调用下同时运行
当子进程先于父进程结束时,子进程会向父进程发送SIGCHLD信号,此时父进程应该去回收子进程的相关资源,如果没有回收,那么子进程就会变成僵尸进程
僵尸进程:该进程已经死亡,但是它的父进程没有立即回收它的相关资源,该进程就进入了僵尸状态
孤儿进程:父进程先于子进程结束,子进程就变成了孤儿进程,此时孤儿进程会被孤儿院(init守护进程)领养,init就是该孤儿进程的父进程
子进程的回收
对于任何结束方式,都希望父进程能够知道,通过wait、waitpid函数可以知道子进程是如何结束的以及结束状态码
进程间通信的分类:(必考)
简单的进程间通信: 信号、文件、环境变量、命令行参数
传统的进程间通信方式:管道文件
XSI进程间通信: 共享内存、消息队列、信号量
网络进程间通信: Socket套接字 本地-socket文件 网络-TCP/IP
匿名管道:
只适合通过fork函数创建的父子进程之间使用
有名管道:
基于有文件名的管道文件的通信
共享内存:
基本特点:
两个或者多个进程之间共享一块由内核负责管理维护的内存,该内存可以与进程的虚拟内存空间进行映射
优点:不需要复制信息,是最快的IPC机制
缺点:需要考虑同步访问问题
信息量:
基本特点:由内核共享维护的一个"全局变量",用于记录共享资源的数量,限制进程对资源的访问
1、如果变量的值大于0,说明可以使用资源,此时需要将变量值-1,然后才能使用资源
2、如果变量的值等于0 ,说明可以资源可以使用,此时进程会进入休眠,直到变量大于0,进程会被唤醒,执行步骤 1
3、当资源使用完毕时,变量的值+1,正在休眠的进程可以被唤醒了
多路复用:
使用一个进程(且只有主线程)同监控若干个文件描述符的读写,这种读写模式叫多路复用。多用于TCP的服务端,用于监控客户端的连接和数据的收发
优点:不需要频繁地创建进程、销毁进程,从而节约了内存资源、时间资源,也避免了进程之间的竞争、等待。
缺点:单个客户端的任务不能太耗时,否则其他客户端就会感知到
适合并发量高,但任务短小的情景,如:Web服务器
select
select设计不合理的地方:
1、每次调用select时都需要向它传递被监控者的信息
2、调用结束后若想知道具体哪些文件描述符发生了相关操作,需要把所有文件描述符都测试一遍,进行轮询
3、select支持的文件描述符数量太小了,默认是1024
select的优点:
它是最早的多路复用函数,几乎所有的操作系统都支持,程序的兼容性高
poll
poll的实现和select非常相似,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制
epoll
优点:
1、只需要拷贝一次描述符
2、会把发生事件的描述符返回,不需要遍历所有的描述符
3、编程结构简洁
进程和线程的区别
1、进程是资源分配的最小单位,线程是程序执行的最小单位(资源调度的最小单位)
2、进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。
而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
3、线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
4、但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
什么情况下使用多进程和多线程:
1、需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的
2、线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
3、因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程
4、并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求
5、需要更稳定安全时,适合选择进程;需要速度时,选择线程更好
因为我的项目中需要对数据段的数据共享,可以被多个程序所修改,所以使用线程来完成此操作,无需加入复杂的通信机制,使用进程需要添加复杂的通信机制实现数据段的共享,增加了我的代码的繁琐,而且使用线程开销小,项目运行的速度快,效率高。
如果只用进程的话,虽然安全性高,但是对代码的简洁性不好,程序结构繁琐,开销比较大,还需要加入复杂的通信机制,会使得我的项目代码量大大增加,切换速度会变的很慢,执行效率降低不少。
什么是死锁
多个进程或线程互相等待对方我资源,在得到对象的资源之前,都不会释放自己的资源,这种造成循环等待的现象叫死锁。
产生死锁的四大必要条件
a、资源互斥不能共享
b、占用且等待
c、资源不可剥夺
d、环路等待
防止产生死锁方法
1、破坏互斥条件
想办法让资源能够共享,解决方法就是增加资源,缺点:如果资源是硬件,可能会有经济上的浪费。
2、破坏请求并保持条件
在程序运行前一次分配所有它所需要的资源,否则不执行,缺点:可能会浪费系统资源,因为有些资源可能短时间用不上。
3、破坏不可剥夺的条件
当请求新的资源失败时释放旧的资源,过一段时间后再重新获取所有资源,缺点反复的释放申请资源会浪费时间。
4、破坏循环等待的条件
把所有的资源进行编号,所有线程按照顺序进行请求资源,缺点:编号必需要要稳定,这样就限制的新的资源加入。
死锁的检测
1、画出资源的分配图
2、简化资源分配图
3、按照产生死锁的四大条件来检查是有请求环路
TCP和UDP的区别
TCP 是面向连接的传输层协议,传输数据前先要建立连接。
UDP 是不需要连接,即刻传输数据。
TCP 是一对一的两点服务,即一条连接只有两个端点。
UDP 支持一对一、一对多、多对多的交互通信
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。
UDP 是尽最大努力交付,不保证可靠交付数据。
TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使用了「选项」字段则会变长的。
UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
TCP 是流式传输,没有边界,但保证顺序和可靠。
UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输效率非常差,所以通常 UDP 的报文应该小于 MTU。
TCP 和 UDP 应用场景:
由于 TCP 是面向连接,能保证数据的可靠性交付,因此经常用于:
FTP 文件传输
HTTP / HTTPS
由于 UDP 面向无连接,它可以随时发送数据,再加上UDP本身的处理既简单又高效,因此经常用于:
包总量较少的通信,如 DNS 、SNMP 等
视频、音频等多媒体通信
广播通信