Linux 开发系列笔记(3.3) - 锁与线程同步
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
锁与线程同步
互斥锁
互斥锁概述
互斥锁(mutex)即任一时刻最多允许一个线程独占资源。一把互斥锁最多被一个线程持有,持有互斥锁的线程具有访问和修改资源的权限,否则线程不应继续访问和修改相应资源,阻塞等待互斥锁释放或运行其他代码。
互斥锁实际是对线程是否进入或阻塞在某段代码的控制,而此段代码所涉及的资源不是互斥锁关注的问题,是程序员应当考虑的问题。
互斥锁函数
man文档中找不到以下mutex相关函数。
pthread_mutex_init、pthread_mutex_destroy
1234567891011121314151617#include <pthread.h>// initialize a mutex// mutex:// structure of mutex// mutexattr:// NULL is enough// return value:// ...
Linux 开发系列笔记(3.2) - 线程基本操作
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
线程基本操作
编译包含线程函数的程序,需要导入动态库-l pthread。(部分版本会自动导入)
查看线程
查看进程线程
1$ ps -Lf <pid> // 查看 pid 进程线程
获取当前线程号
12345#include <pthread.h>// get the thread identifier// return value:// pthread identifier, always succeedpthread_t pthread_self(void);
比较线程号
123456789#include <pthread.h>// compare thread identifier// t1:// thread identifier 1// t2:// thread identifier 2// return ...
Linux 开发系列笔记(3.1) - 线程概述
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
线程概述
线程(Thread)本质上是轻量级进程(LWP,Light Weight Process),但与进程拥有不同的行为。在Linux中线程被当作进程进行处理,在原生Linux中并不支持线程。现在Linux操作系统上的线程,大多是Red Hat基于POSIX开发的NPTL(Native POSIX Tread Library)。
线程是轻量级进程。在进程创建时虽然运用写时拷贝技术大幅度减少了拷贝量,但仍然需要拷贝PCB中诸如虚拟内存映射表以及文件描述符表中的数据;线程共享PCB,这意味着线程创建时拷贝的数据量很小,创建线程的开销通常是进程创建的1/10或者更少。
线程依然具有不共享资源:
线程号与线程的实时调度策略与优先级
信号掩码
线程特有数据
errorno变量(线程操作中,errorno通过函数返回,而非设置全局变量)
栈空间与.text空间(线程运行在函数体中,因此外部无法访问函数体数据与代码)
与进程不同地,进程拥有父子关系构成的复杂进程树结构,而线程仅拥有主线程与子线程的二 ...
Linux 开发系列笔记(2.4) - 守护进程
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
守护进程
进程、进程组、会话
关联与权限
进程间管理模式不仅包含父子关系,还包含如进程、进程组、会话如此的组关系,会话包含进程组、进程组包含进程。
进程的组关系与父子关系间不存在依赖关系,即任何亲缘关系的进程可以存在任意的组关系。但进程的组关系在逻辑上与亲缘关系有一定的默认联系:
使用bash启动进程
pgid(进程组ID):设置为pid
sid(会话ID):设置为bash进程的sid
使用fork创建进程:
pgid:设置为父进程的pid
sid:设置为父进程的sid
也就是说,bash会为启动进程创建新的进程组,fork在原进程组下创建进程。
权限:一个会话中至多有一个进程组占用控制终端(具有控制权的终端),这也是会话名称的由来;进程通常只有操作自己与子进程的pgid与sid的权限,否则抛出Operation not permitted错误。
组关系管理函数
getpgid、setpgid
123456789101112131415161718192021#include < ...
Linux 开发系列笔记(2.3) - 进程通信
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
进程通信
进程通信概述
进程是一个独立的资源分配单元,不同进程间的资源是分别独立的。每个进程拥有独立的内存映射表,一个进程无法直接访问另一个进程的数据。
进程通信(IPC,Inter Process Communication)用于完成进程间信息交互和状态传递,从而实现数据传输、资源共享、信号传递、调试控制等功能。
进程通信主要包括本机进程通信与远程进程通信,本章节将介绍本机进程通信,包括:匿名管道、有名管道、信号、消息队列、内存映射、共享内存、信号量。
管道(匿名管道)
管道概述与原理
管道基本结构
管道文件位于内核区,是Linux进程间通信最古老的方式之一,用于实现拥有 公共祖先 的进程间通信 。
管道(Pipe、匿名管道)是一个拥有一个读端与一个写端的队列数据结构(其底层实际为循环队列),具有先入先出的特点,管道内的数据以流的形式存在,称为管道流。管道具有内存限制,可以认为是管道通信模式的中转站与缓冲区。
管道是一个半双工的工作模式,但通常以单工模式通信。
单工:仅可用于单向数据传 ...
Linux 开发系列笔记(2.2) - 进程基本控制
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
进程基本控制
进程创建、进程查看、进程重载、进程调试、进程回收
进程状态命令
查看与设置进程资源限制
123$ ulimit -a // 查看全部进程资源限制// About more of shell command: "ulimit --help" or "help ulimit"// About more of linux api: "man 2 getrlimit" or "man 2 setrlimit"
查看进程状态快照
1$ ps aux // 或 ps ajx
(默认):显示当前终端进程及其子进程的粗略信息。
a:显示终端上的所有进程,包括其他用户进程。
x:显示无终端的所有进程,不包括其他用户进程。
u:显示进程详细信息。多为用户关注信息,如:CPU占用、内存占用、STAT状态。
j:显示进程详细信息。多为控制相关信息,如:PPID、GID、STAT状态。
STAT状态:
1 ...
Linux 开发系列笔记(2.1) - 进程概述
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
进程概述
程序与进程
程序:包含一系列二进制信息的文件,用于描述如何创建一个进程。程序存储于磁盘中。包含:二进制格式标识、程序入口地址、机器码指令、数据、符号表与重定位表(如调试信息)、共享库与动态链接信息、其他。
进程:进程是正在运行的程序,一个程序的实例,占用内存与CPU等资源。进程是一个程序关于某个数据集的运行活动,是传统操作系统中基本的分配单元与执行单元。
PCB(Processing Control Block):内核中一个复杂的数据结构,用于描述进程的运行状态,包含:进程标识、进程状态、虚拟内存表、文件标识符表、信号传递与处理有关信息、进程资源使用与限制信息、当前工作目录、其他。
PCB的定义源码见/usr/src/linux-headers-xxx/include/linux/sched.h::task_struct。
并发与多道程序
单道程序:早期计算机仅支持一个程序在计算机上运行,不支持多个程序同时运行。它是效率低下的。
多道程序:通过时序控制程序,使多个程序任务穿插进行, ...
Linux 开发系列笔记(1.7) - 虚拟内存地址
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
虚拟内存地址
整理自:为什么需要虚拟内存?_小林coding的博客-CSDN博客
虚拟地址
为什么需要虚拟地址?
在做单片机时,因为没有操作系统的存在,我们通常直接访问物理内存地址(Physical Memory Address),程序需要烧录到单片机中。如果在同一个单片机中,同时运行两个程序,那么这时就可能会出现各种错误。产生错误的原因就是为两个程序分配了包含相同的物理内存地址,两者的数据相互干预。
现代计算机应用程序建立在操作系统之上,操作系统为我们完成了这部分冲突的解决,使得多道程序同时在操作系统上运行,而使得在应用程序开发中基本无需关心物理内存地址冲突的问题。
解决这一问题的技术虚拟内存地址(Virtual Memory Address)、以及由此衍生出的内存分段(Segmentation)与内存分页(Paging)技术,就是本章讲解的内容。需要注意的是,虚拟内存由内核而无需用户关注,本章讲解的均为原理。
虚拟地址空间
虚拟内存映射表表存储于PCB中,每个进程都拥有一个虚拟内存映射表,不同进程 ...
Linux 开发系列笔记(1.6) - 文件操作与目录操作
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
文件操作与目录操作
基本原理
标准C库与Linux系统文件IO对比
I0:Input / Output,输入输出,通常指文件在存储介质之间的传输。
标准C库IO函数与LinuxIO函数是调用与被调用的关系, 标准C库函数调用Linux函数进行文件IO,应用程序没有直接操作文件的权限,必须由操作系统代理完成。标准C库IO函数比LinuxIO函数更高级。但是,需要注意的是,标准C库 IO函数效率高于 Linux 函数,标准C库 为IO实现了 缓冲区 的功能,减少了效率低下的外部设备访问开销。
由于缓存区的存在,标准C库IO是非即时的,LinuxIO是即时的,例如在网络交互中需要使用后者,一般场景使用前者更优。
虚拟地址空间
在操作文件与内存中得到的所有地址都是虚拟地址,真实地址对于用户是不可见的,也是无需关心的。
MMU:Memory Management Unit,用于实现虚拟地址与真实地址之间的映射,从而完成CPU的内存管理请求。虚拟地址映射表存储在PCB中。
栈空间从高地址向低地址占用 ...
Linux 开发系列笔记(1.5) - GDB 基本使用
建站提交历史文章,原文写作时间 2023 年 2 月前后。
回到文章目录
GDB 基本使用
介绍
GDB是GNU提供的调试工具,是最原始的调试工具。
本章节将简单介绍GDB的使用,满足基本需求。
关于更多内容:
1(gdb) help // 查看帮助
生成可调试文件
1$ gcc main.c add.c sub.c mul.c div.c -o main -g -Wall // 必须开启 -g, 建议开启 -Wall
-g将建立可调试文件,在可执行文件中嵌入源代码与机器码映射关系。
调试建立发生在编译环节,即预处理代码 →\to→ 汇编代码环节,也可以对汇编代码建立调试,将嵌入汇编代码与机器码映射关系(即后续调试将是对汇编代码的调试)。可以对不同文件选择性建立调试,再连接成完整文件。
-g建立的可调试文件体积通常大于一般可执行文件。
可调试文件与源文件建立了映射关系,调试时需确保源文件在原始位置(绝对路径),未删改。
常用命令
启动与结束
1234$ gdb <file> // 启动 GDB$ gdb <file> -d <director ...