声明:本文内容纯属博主自己查找和归纳的个人所需的知识点,仅作参考,如有错误,博主强烈希望您指出。如果您是某个知识点的原创博主,如有需要,可联系本人加上链接。本文内容会根据博主所需进行更新,希望大家多多关照。
文件IO相关知识点
- 七种文件类型:普通文件(-)、目录(d)、符号链接(l)、管道(p)、套接字(s)、字符设备(c)、块设备(b)
- shell中文件的颜色:白色——普通文件、绿色——可执行文件、红色——压缩文件、蓝色——目录、青色——链接文件、黄色——块设备字符设备管道、灰色——其他文件
- PCB:进程控制块,存放文件描述符表,本质是一个结构体
- PCB内部成员:进程ID、进程状态、当前工作目录、文件描述符表、用户ID组ID、信号相关的信息等
- 一个进程有一个文件描述符表,大小为1024字节,前三个被占用,分别是STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO
- 文件描述符作用:寻找磁盘文件
- 查看磁盘命令:
df -h
并发与并行
- 并发:
是指同一个时间段内多个任务同时都在执行,并且都没有执行结束。并发任务强调在一个时间段内同时执行,而一个时间段由多个单位时间累积而成,所以说并发的多个任务在单位时间内不一定同时在执行 。
- 并行:
是说在单位时间内多个任务同时在执行。
在多线程编程实践中,线程的个数往往多于CPU的个数,所以一般都称多线程并发编程而不是多线程并行编程。
进程相关知识点
- 查看进程:
ps aux
,ps ajx
能显示父进程,查看内存占用:free -h
,查看当前cpu:top
- MMU:虚拟内存映射单元,单位为4k,虚拟内存通过MMU映射到物理内存
- 寄存器4字节,1字节8位
- 进程基本状态:初始态、就绪态、运行态、挂起态、终止态
运行态->挂起态:等待使用资源,如等待外设传输、人工干预等
运行态->就绪态:出现有更高优先权进程
- 父子进程共享:文件描述符、mmap映射区、全局变量读时共享、写时复制
- 孤儿进程:父进程先于子进程结束,子进程称为孤儿进程,init进程变为它的父进程并接管孤儿进程
- 僵尸进程:当子进程比父进程先结束,而父进程又没有回收子进程,子进程的进程描述符仍然保存在系统中,此时子进程将成为一个僵尸进程
进程间通信相关知识点
- 进程间常用的4种通信方式:管道(使用简单)、信号(开销小)、共享映射区(无血缘关系可用)、本地套接字(稳定)
- 管道:
本质为一个伪文件,内核使用环形队列机制,借助内核缓冲区(4k)实现,数据一旦读走,管道中不在存在
- 共享映射区:
mmap,一种内存映射文件的方法,将一个文件或者其它对象映射进内存,无血缘关系的进程间可使用共享映射区进行通信,在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关
- 信号:
简单但不能携带大量信息,满足条件才发送,相当于中断,有很强的延时性,所有信号都由内核(PCB)发送和处理
信号4要素:编号、名称、事件、默认处理动作
信号处理方式:执行默认动作(终止进程、忽略信号、终止进程并生成CORE文件、暂停进程、继续运行进程)、忽略、捕捉
- 查看信号列表:
kill -l
创建会话要注意什么
- 创建会话的进程不能是进程组组长,否则出错返回
- 该进程变成新会话的首进程和一个新进程组组长
- 需要有root权限(Ubuntu不需要)
- 新会话丢弃原有的控制终端,该会话没有控制终端
- 创建会话时,先调用fork,父进程终止,子进程再调用setsid()
创建守护进程
- 在父进程中执行fork并exit退出;
- 在子进程中调用setsid函数创建新的会话;
- 在子进程中调用chdir函数,让根目录 "/" 成为子进程的工作目录;
- 在子进程中调用umask函数,设置进程的umask为0;
- 在子进程中关闭任何不需要的文件描述符(close(fd))或者重定向"/dev/null"
线程相关知识点
- 查看所有线程:
top -H
;ps -Lf
进程号,查看该进程的线程 - 线程定义:LWP,轻量级进程,有独立的PCB和共享地址空间
- 为什么会出现线程安全:当一个线程在操作共享资源时,未执行完毕的情况下,其他线程参与进来,导致共享资源出现安全问题。
- 保护共享数据区方法:互斥量、读写锁、条件变量、信号量(C语言)、原子操作(通常用来保护单个变量)、windows临界区
- 死锁:对一个锁反复Lock,或者2个线程各自锁上一把锁后请求对方的锁
- 死锁解决方法:按同样的顺序上锁,c++11用std::lock(mutex1, mutex2, ...)
条件变量的使用
- 创建一个互斥量,用lock_guard或者unique_lock封装互斥量
- 创建条件变量,用wait成员函数等待条件满足
- 另一线程使用notify_one或notify_all后激活wait
- wait拿锁后判断第二个参数是否为true,如果true则执行下面的代码,如果false则表示条件不满足,继续等待下次的激活
sleep()和wait()的区别
- sleep()包含<windows.h>头文件,wait()包含<wait.h>文件
- sleep()占着CPU休眠,不会解锁,wait()释放锁并腾出CPU资源等待唤醒并拿锁
进程与线程的区别
- 进程是分配资源的基本单位;线程是系统调度和分派的基本单位。
- 一个进程可以拥有多个线程,属于同一进程的线程,具有相同的地址空间,堆是共享的,栈是私有的。
- 进程开销大,线程开销小
- 线程间通信相对方便,进程间通信相对复杂
- 多进程更健壮,多线程容易出错
- 进程是一个资源的容器,为进程里的所有线程提供共享资源,是对程序的一种静态描述,线程是计算机最小的调度和运行单位,是对程序的一种动态描述
为什么使用多线程
- 避免阻塞
单个线程中的程序,是顺序执行的。如果前面的操作发生了阻塞,那么就会影响到后面的操作。这时候可以采用多线程
- 避免CPU空转
有时候处理一条请求,会涉及到数据库访问、磁盘IO等操作,这些操作的速度比CPU慢很多,而在等待这些响应的时候,CPU却不能去处理新的请求,没有充分利用资源,这时多线程就发挥作用了
- 提升性能
在满足条件的前提下,多线程确实能提升性能:
第1,任务具有并发性,子任务之间不能有先后顺序的依赖,必须是允许并行的,另外,还不能有资源竞争
第2,只有在CPU是性能瓶颈的情况下,多线程才能实现提升性能的目的。
第3,就是需要有多核CPU才行,如果上述条件都满足,有一个经验公式可以计算性能提升的比例,叫阿姆达尔定律:
速度提升比例 = 1/[(1-P)+(P/N)]
其中P是可并行任务的比例,N是CPU核心数量
gdb基础调试
编译:gcc加要加-g,-g保留函数名和变量名
启动:gdb 可执行文件
传参:set args 参数1 参数2 ...
操作 | 命令 |
---|---|
查看第n行的上下程序 | l n |
设置查看n行上下程序 | set listsize n |
查看其他文件程序 | l 文件名 : n 或 函数名 |
在n行打断点 | b n |
查看断点 | i b |
删除断点 | d n,n为断点编号 |
设置无效或有效断点 | dis / enb n,n为断点编号 |
条件断点 | b n if 变量==值 |
运行 | r 或 start,r直接到断点,start进入程序第一行 |
单步执行 | n |
执行到下一个断点 | c |
查看变量信息 | p 变量名 |
查看变量类型 | ptype 变量名 |
一直显示变量信息 | display 变量名 |
取消显示变量 | 先i display 查看变量编号n,然后undisplay n |
进入函数 | s |
离开函数 | finish |
跳出循环 | until,需要删除断点 |
离开gdb | q |
gdb也可以直接调试core文件查看错误:
1.当一个程序出现段错误时,会出现以下提示:
Segmentation fault (core dumped)
core 指该程序运行时,进程空间的内存分布
dumped 表示内核已经把core抛出
通常,出现段错误提示时程序运行目录下应该自动生成一个core文件用来存储内核抛出的core,但是,由于linux环境一般默认设置core文件限制为0,所以一般情况下无法生成core文件。
2.查看core文件大小限制:ulimit -c
3.将其修改为无限制:ulimit -c unlimited
4.运行命令:gdb 执行文件名 core
5.gdb输入 where
gdb多线程调试
命令行查看线程信息:
- 查看当前运行的进程:
ps aux|grep 执行文件名
- 查看当前运行的轻量级进程:
ps -aL|grep 执行文件名
- 查看主线程和新线程的关系:
pstree -p 主线程id
线程栈结构的查看:
- 获取线程ID
- 通过命令查看栈结构:
ps stack 线程ID
利用gdb查看线程信息:
- 将运行着的进程附加到gdb调试器当中,查看是否创建了新线程:
gdb attach 主线程ID
进入gdb调试:
-
info inferiors
:查看当前进程 -
info threads
:查看当前线程 -
bt
:查看当前线程栈结构 -
thread n/ID
:切换线程(n代表第几个线程) -
break 行号/函数名
:设置当前线程断点 -
break file.c:100 thread all
:在file.c文件第100行处为所有经过这里的线程设置断点。 -
set scheduler-locking off/on/step
:
在使用step或者continue命令调试当前被调试线程的时候:
off:不锁定任何线程,也就是所有线程都执行,这是默认值。
on:只有当前被调试程序会执行。
step:在单步的时候,除了next过一个函数的情况以外(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为),只有当前线程会执行。 -
thread apply ID1 ID2 command
:让一个或者多个线程执行GDB命令command -
thread apply all command
:让所有被调试线程执行GDB命令command
makefile基础
- 向下检索内容,根据时间判断哪个文件需要更新
- 目标:依赖
命令 - 查找目录下指定文件类型:
变量 = $(wildcard 文件路径)
- 匹配替换:
变量 = $(patsubst 原名称, 替换后的名称, 源文件)
-
notdir
:去除文件名的目录函数 -
basename
:取文件名函数 -
$@
:规则中的目标$<
:规则中的第一个依赖$^
:规则中所有依赖 -
/
:换行 - 自定义命令:
名称:
命令 - 声明伪目标:
.PHONY:名称
随便说一下Linux和Windows的区别
- 兼容性:windows向后兼容,linux内核升级可能就不兼容,软件方面windows占优
- 进程:单个进程windows不能执行,linux可以
- 性能:windows图形界面,很多渲染,性能降低,linux少,用命令行工作,性能好
- 文件系统:linux有多种文件系统,对文件和设备的管理占优,windows较差
- 中断优先级:windows有32级,linux似乎只有5级,异常分为故障(fault)、陷阱(trap)和中止(abort)
- 软件启动:windows用注册表,linux用配置文件,灵活性高
有疑问加站长微信联系(非本文作者)