
Linux系统编程
文章平均质量分 89
qq_52484093
这个作者很懒,什么都没留下…
展开
-
属性编程与权限编程
struct stat 结构体中的 st_mode 字段记录了文件的访问权限位。文件的物理载体是硬盘,硬盘的最小存储单元是扇区 (每个扇区 512 字节)文件元信息 (创建者、创建日期、文件大小,等) 存储于 inode 区域。设置用户 ID :文件权限中的特殊标志位 (二进制 bit 位)实际用户 ID (EUID) :决定用户对系统资源的访问权限。文件系统以 块 为单位(每个块 8 个扇区) 管理文件数据。如何获取文件的大小,时间戳以及类型等信息?文件的权限可分为 普通权限 和 特殊权限。原创 2025-02-02 18:50:22 · 408 阅读 · 0 评论 -
Linux文件原生操作
Linux 中一切皆文件,那么 Linux 文件是什么?在 Linux 中的文件可以是:传统意义上的有序数据集合,即:文件系统中的物理文件也可以是:设备,管道,内存。。。(Linux 管理的一切对象)原创 2025-01-29 21:51:13 · 526 阅读 · 0 评论 -
深入理解文件描述符
计算机中用于组织、存储和管理文件的数据结构集合管理磁盘或其他存储介质上的空间 (将存储介质分块管理)保证文件数据不被破坏,确保数据的一致性和完整性为用户和应用程序提供了访问和操作文件的标准化接口方便地创建、删除、修改、重命名文件实现对文件的读写以及权限控制等功能。原创 2025-01-29 22:27:48 · 437 阅读 · 0 评论 -
Linux文件基本操作
文件是具有永久存储性,按特定字节顺序组成的命名数据集文件可分为:文本文件,二进制文件文本文件:每个文件存放一个 ASCII 码存储量大,速度慢,便于对字符操作二进制文件:数据按照在内存中的存储形式原样存放存储量小,速度快,便于存放中间结果test3.cint main()exit(1);fclose(fp);return 0;原创 2025-01-28 12:03:01 · 944 阅读 · 0 评论 -
多线程编程杂谈( 下)
取消点即特殊函数的调用点线程允许取消并且取消类型是延迟取消当接收到取消请求后,执行到特殊函数调用点时,线程退出常用取消点函数在需要退出的 "关键点" 调用此函数,线程返回值为 PTHREAD_CANCELED必须在线程中调用取消状态和取消类型的设置函数除了 pthread_testcancel() 函数, sleep() 函数也是取消点线程接收取消请求后,会执行线程清理函数 (释放资源)进入临界区之前,将取消状态设置为 PTHREAD_CANCEL_DISABLE。原创 2025-01-27 11:11:47 · 1033 阅读 · 0 评论 -
多线程编程杂谈(上)
该程序创建100个线程,每个线程会对全局变量 g_var 进行 10000次加一操作,但由于 g_var 是全局变量,是临界资源,并且 g_var++ 操作不是原子操作,g_var++ 在汇编层面分为三个步骤,首先是将 g_var的值读到某个寄存器上,然后是在寄存器上对这个值加一,最后将加一后的值写入到 g_var,所以这个程序的运行结果的打印,g_var 的值会小于等于 1000000。第 11 行,我们将 g_var 通过 _Atomic 关键字将它修饰为原子变量,对 g_var 的操作不可被打断。原创 2024-12-15 18:48:44 · 893 阅读 · 0 评论 -
多线程局部存储技术
在两个线程中打印 g_global 的地址和值。但在后续的子线程在函数调用的时候,我们需要将指向 ThreadGlobal 类型的指针作为函数的参数传入来区分每个线程专属的全局变量,这边我们使用了宏定义,优化了这个问题。第 67 行,在创建子线程的时候,我们会 malloc 一个 ThreadGlobal 这个结构体,将这个指针传入每个子线程,这样每个子线程都有唯一的变量。第 10 行,我们通过 __thread 关键字来修饰变量 g_global,使得 g_global 变量在每个线程都有一份拷贝。原创 2024-05-05 16:58:32 · 325 阅读 · 0 评论 -
多线程与信号量简介
第 53 行,get_shared_memory() 函数调用了 shmget() 函数,shmget() 是一个Linux系统调用函数,用于创建一个新的共享内存段(segment)或获取一个已存在的共享内存段。子线程读完以后,信号量 w 的值会加一,主线程才能去写;由于信号量的初始值为 1,所以只能有一个子线程获取到信号量,其它的线程来获取信号量时,发现信号量的值为 0,就会阻塞等待信号量被释放。该程序中使用的两个信号量,信号量 w 和信号量 r,信号量 w 的初始值为 1,信号量 r 的初始值为 0。原创 2024-05-04 16:40:04 · 781 阅读 · 0 评论 -
线程同步与条件变量
第 54 行,如果生产者生产了产品后发现上一次的产品没了,则调用 pthread_cond_signal(&g_cond),来唤醒阻塞在 g_cond 这个条件变量上的单个消费者线程来取产品,这样原先阻塞在 g_cond 这个条件变量上的某个线程就会被唤醒,重新抢夺互斥锁,取走产品,然后释放互斥锁。第 24 行,如果消费者发现没有产品,则调用 pthread_cond_wait(&g_cond, &g_mutex) 阻塞在 g_cond 这个条件变量上,并释放已获取到的互斥锁 g_mutex。原创 2024-05-02 16:39:31 · 893 阅读 · 0 评论 -
多线程读写锁应用
无论是 "读锁" 还是 "写锁",解锁都是调用 pthread_rwlock_unlock()如果两个线程 "同时" 拿到了 "读锁" 和 "写锁",问:哪个线程先进入临界区执行?读写锁在实现上比互斥量复杂,单纯的 "上锁" 和 "解锁" 操作读写锁相对互斥量低效。因此,针对多线程 "读" & "写" 场景需要更具针对性的解决方案。问题:互斥量可用于多线程 "读" & "写" 共享变量的场景吗?保护临界区时,必须清楚当前需要使用 "读锁" 还是 "写锁"读优先:拿到 "读锁" 的线程优先进入临界区。原创 2024-02-23 17:22:40 · 537 阅读 · 1 评论 -
活锁方案与自旋锁
当超时未能获取目标锁,则让出处理器使用权,线程进入阻塞状态。自旋锁与互斥量类似,在任何时刻,最多只能有一个持有者。轻量级锁定,即:临界区相对短小,自旋锁持有时间非常短。即:线程 获取锁 到 释放锁 的时间内只有一个执行流。自适应锁相对普通互斥量效率更高,相对自旋锁安全性更好。线程一旦获取自旋锁,则不能让出处理器使用权。如果只有一个单核处理器,不建议使用自旋锁。自适应锁先以自旋的方式持续尝试获取目标锁。线程获取互斥量失败后究竟发生了什么?如何设置获取互斥量时的等待时间?一种特殊的互斥量,又名:自适应锁。原创 2024-02-05 17:28:56 · 507 阅读 · 0 评论 -
多线程互斥量进阶
假设有 三个线程 (A,B,C) 和三个互斥量 (R,S,T),三个线程对互斥量的获取及释放如下,问:是否可能发生死锁?一个线程多次尝试获取同一个互斥量,会发生什么?破坏死锁条件中的任意一个!原创 2024-02-02 10:29:17 · 405 阅读 · 0 评论 -
排队模型应用案例
定义任务结构体 (CurTask) 模拟顾客 (CurTask 变量表示具体客户)方案:将多个线程预先存储在一个 "池子" 内,当需要线程时直接从 "池子" 取出。使用队列数据结构表示等待队列,队列中存储 CurTask 变量 (顾客排队模拟)各个线程从队列中取任务时是互斥操作 (每次只能一个线程操作队列)如何模拟等待中的顾客 (即:如何模拟待执行的任务)?利用线程池模拟工作窗口,每个线程表示一个工作人员。如何模拟工作窗口 (即:如何模拟工作人员)?线程从队列中取出任务执行 (服务客户模拟)原创 2024-02-01 16:47:33 · 403 阅读 · 0 评论 -
初识多线程互斥量
这种操作一旦开始,就一直执行到结束,中途不会被打断原子操作可以是一个步骤,也可以是多个步骤的集合原子操作的顺序不可以被打乱,也不可以被切割而只执行其中的一部分原子操作在多 任务/线程 并发时能够保证操作结果的正确性。原创 2024-02-01 15:43:08 · 304 阅读 · 0 评论 -
线程的连接与分离
pthread_join() 等待的线程必然是 pthread_create() 创建的线程。父进程调用 wait() / waitpid(),为子进程 "收尸" 处理并释放暂留资源。pthread_join() 除了等待线程执行结束,还会释放线程所占用的资源。线程进入分离状态,其它线程无法连接 (不可等待 且 无法获取返回值)线程的分离状态指线程不可能执行连接操作 (并非脱离进程不可控)可连接的线程退出后需要执行连接操作,否则线程资源无法释放。分离状态的线程退出后主动释放系统资源 (常规需求)原创 2024-02-01 13:52:33 · 487 阅读 · 0 评论 -
Linux线程API详解(下)
pthread_cleanup_push() 和 pthread_cleanup_pop() 之间构成内部作用域。pthread_exit() 与 pthread_cancel() 总是会触发清理函数执行。pthread_cleanup_pop() 的参数非零时,触发一个清理函数执行。main() 中执行 return 语句,意味着主线程执行结束,因此进程结束。vfork() 进程只是一个新的执行流 (无任何附带资源的执行流)vfork() 不能和父进程同时执行 (父进程等待子进程结束)原创 2024-01-31 14:43:57 · 788 阅读 · 0 评论 -
Linux线程API讲解(上)
线程执行流调用 pthread_exit() 函数 (注意:void exit(int status);其它线程对指定线程调用 pthread_cancel() 函数 (不安全)线程入口函数执行了 return 语句,并返回指定值。该函数用于等待指定的线程 (tid) 执行结束。如果指定线程已经执行结束,则函数调用立即返回。如果指定线程必须不可连接,则函数调用失败。参数 retval 用于接收线程 返回值。原创 2024-01-29 10:37:48 · 487 阅读 · 0 评论 -
深入浅出线程原理
Linux 内核中的基本调度单位为 task_struct,即:内核中以 "任务" 作为调度的基本单位。对于线程来说,pthread_t 类型的标识符 与 pid_t 类型标识有什么不同?每一个线程在内核中都对应一个调度实体,拥有独立的结构体 (task_struct)pid_t pid => 线程标识符 (Thread ID)因此,kill 任意子线程的 pid_t 将导致整个进程结束。进程创建后默认拥有一个线程,即:主线程 (默认执行流)拥有多线程的进程,又被称为线程组 (谁是线程组长?原创 2024-01-12 14:44:37 · 981 阅读 · 0 评论 -
Linux线程编程初步
线程创建函数:int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);创建 / 销毁 线程花费的时间 < 创建 / 销毁 进程花费的时间。进程:应用程序的一次加载执行 (系统进行资源分配的基本单位)多进程程序共享一段内存 => "机制复杂"进程中的多个线程并行执行,共享进程资源!多线程代码复杂度 > 多进程代码复杂度。线程:进程中的程序执行流。原创 2024-01-11 19:43:08 · 450 阅读 · 0 评论 -
浅谈进程优先级(下)
换算关系:规范优先级 = MAX_RT_PRIO - 实时优先级 - 1。PRI = 规范优先级 - 40 = 59 - rt_priority。对于实时进程而言,内核模式的优先级与用户模式的优先级并不同。PRI = 规范优先级 - 40 + nice_value。将父进程设置为实时进程,且实时优先级为 99 (调度器)对于实时进程,设置 nice_value 会发生什么?父进程进入循环调度,根据时间片定义改变子进程的调度策略。在优先级不同的时候,先执行优先级高的进程。如何定制实时进程的执行时间?原创 2024-01-08 17:43:25 · 723 阅读 · 0 评论 -
浅析进程优先级(上)
进程优先级:将处理器资源分配给进程的先后顺序Linux 中每个进程都有相应的优先级 (优先级可能动态改变)进程优先级决定进程 何时执行 和 获得处理器的时间进程优先级通常表现为一个整数值 (数值大小决定优先级高低)原创 2024-01-08 14:15:14 · 1076 阅读 · 0 评论 -
多核调度实验设计
吞吐量存在理论上限值,进程数量多余处理器数量时,吞吐量只能逼近理论上限值。执行进程数量 处理器数量:延迟增加,吞吐量不变。如何验证处理器,进程数量,吞吐量之间的关系?执行进程数量 = 处理器数量:吞吐量达到顶峰。原创 2024-01-04 16:27:47 · 415 阅读 · 0 评论 -
多核调度预备知识
ps -- 查看进程运行时数据 (ps au)top -- Linux 整体性能监测工具 (类似任务管理器)sar -- Linux 活动情况报告 (系统性能分析工具)原创 2024-01-03 17:53:43 · 1029 阅读 · 0 评论 -
初探Linux进程调度
Linux 系统中可以使用 chrt 命令来查看、设置一个进程的优先级和调度策略命令用法主要参数-p, --pid 操作一个已存在的 PID,不启动一个新的任务-f, -fifo 设置调度策略为 SCHED_FIFO-m, --max 显示最小和最大有效优先级,然后退出-o, --other 设置调度策略为 SCHED_OTHER-r, --rr 设置调度策略为 SCHED_RR。原创 2024-01-02 10:45:48 · 398 阅读 · 0 评论 -
信号处理设计模式
线程创建函数:int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);先屏蔽所有信号 (无法递达进程),之后为屏蔽信号创建文件描述符;当时机成熟,通过 read() 系统调用读取未决信号 (主动接收信号)由于给每个信号唯一的标记位置,因此,所有信号转变为不可靠信号;其他线程:首先屏蔽所有可能的信号,之后执行任务代码。每个线程拥有独立的信号屏蔽掩码。原创 2023-12-26 16:51:38 · 1600 阅读 · 1 评论 -
信号优先级与安全性
方案:对目标进程发送 N 次 "无" 序信号,验证信号递达进程的先后次序。不要在信号处理函数中调用不可重入函数 (即:使用了全局变量的函数)对于同一个进程,如果存在两个不同的未决实时信号,那么先处理谁?当信号递达,转而执行信号处理函数时,不可重入的函数不能调用。信号的本质是一种软中断 (中断有优先级,信号也有优先级)不要调用函数中存在临界区的函数 (可能产生竞争导致死锁)不要调用标准 I/O 函数,如:printf() 函数。对于不同的未决实时信号,信号值越小优先级越高。目标:验证信号的优先级。原创 2023-12-25 10:36:32 · 941 阅读 · 0 评论 -
信号可靠性剖析
信号 32 与信号 33 (SIGCANCEL & SIGSETXID) 被NPTL 线程库征用。对于 Linux 内核,信号 32 是最小的可靠信号。不可靠信号的默认处理行为可能不同 (忽略,结束)设置信号队列上限:ulimit -i 1000。信号的可靠性由信号数值决定,与发送方式无关。基于信号发送的进程间通信方式可靠吗?查询信号队列上限:ulimit -i。可靠信号的默认处理行为都是结束进程。信号队列的上限可通过命令设置。不可靠信号 (传统信号)可靠信号 (实时信号)原创 2023-12-05 19:57:20 · 1085 阅读 · 0 评论 -
信号发送与处理-下
如果希望信号处理之后,被中断的系统调用能够重启,则:可以通过 errno == EINTR 判断重启系统调用。对于执行时间较长的系统调用 (write / read),被信号中断的可能性很大。对于 System V 风格的 signal 函数,会引起信号处理函数的重入。System V 风格的 signal 函数,注册的信号处理是一次性的。系统调用期间,可能收到信号,此时进程必须从系统调用中返回。进程收到信号后,调用由 signal 注册的处理函数。三种注册信号与处理函数的方法有什么区别?原创 2023-11-08 10:45:36 · 139 阅读 · 0 评论 -
信号发送与处理-上
信号是一种 "软件中断",用来处理异步事件内核发送信号到某个进程,通知进程事件的发送事件可能来自硬件,可能来自用户输入,可能来自除零错误信号是一种类型的进程间通信方式 (一个进程向另一个进程发送信号)A 进程发生事件 T,向 B 进程发送信号,B 进程执行动作响应事件进程可以对接收到的不同信号进行不同响应动作 (信号 => 处理)// 信号处理完毕才返回。原创 2023-11-07 17:10:43 · 160 阅读 · 0 评论 -
守护进程深度分析
守护进程是系统中执行任务的后台进程不与任何终端相关联 (不接收终端相关的信号)生命周期长,一旦启动,正常情况下不会终止 (直到系统退出)Linux 大多服务器使用守护进程实现 (守护进程名以后缀 d 结尾)原创 2023-10-22 12:03:14 · 227 阅读 · 0 评论 -
Linux 进程层次分析
/ 设置进程的组标识。// 获取指定进程的组标识。进程组可方便进程管理 (如:同时杀死多个进程,发送一个信号给多个进程)pid_t getpgrp(void);// 获取当前进程的组标识。每个进程都有一个进程组号 (PGID)原创 2023-09-25 17:27:07 · 371 阅读 · 0 评论 -
Linux 终端与进程
打开 PTY 从设备:slave = open(path_to_slave, O_RDWR);创建 PTY 主从设备:master = posix_openpt(O_RDWR);Linux 中的 终端,控制台,TTY,PTY 究竟是什么?TTY 演变为 Linux 中的抽象概念,对于进程而言 TTY 是一种输入输出设备。终端必然与进程关联才有意义!终端是一台独立于计算机的机器,是能够和计算机进行交互的设备。控制台是一个直接控制设备的面板 (属于设备的一部分)计算机上的输入设备和显示设备从主机独立出来。原创 2023-09-20 16:35:40 · 350 阅读 · 0 评论 -
进程创建大盘点
程序崩溃是因为 vfork() 后,子进程和父进程共享同一个进程空间,第 31 行,子进程 return 0 之后,会从创建点返回,破坏栈结构,使得父进程的栈空间被破坏掉,从而导致程序崩溃。我们在 fork() 之后,立即执行 execve() 的话,fork() 复制父进程进程空间的操作是多余的,因为 execve() 会覆盖复制出来的父进程进程空间。vfork() 后,子进程共享父进程的地址空间,父进程会等待子进程运行结束后,再向下运行。子进程可以使用父进程的数据 (堆,栈,全局)原创 2023-07-31 10:55:01 · 142 阅读 · 0 评论 -
深入 Linux 进程
pid 为 368521 的子进程,通过 exit(-1) 来退出,退出状态码应该为 -1,而 wait(...) 函数中得到该进程的退出状态码却为 0xFF00,这是因为退出状态码由多个部分组成。在命令行中通过 echo $?命令成功获取到了 a.out 这个子进程的进程退出状态码,那么我们可以在程序中获取到子进程的退出状态码吗?在父进程中,通过 wait(...) 函数来得到子进程的退出状态。我们通过进程退出状态的相关宏,来得知进程是主动退出还是收到信号退出,并打印出对应的退出状态值或退出信号值。原创 2023-07-17 10:58:59 · 223 阅读 · 0 评论 -
环境变量编程
环境变量是进程运行过程中可能用到的 "键值对" (NAME = VALUE)进程拥有一个环境表 (environment list),环境表包含了环境变量环境表用于记录系统中相对固定的共享信息 (不特定于具体进程)进程之间的环境表相对独立 (环境表可在父子进程之间传递)原创 2023-07-03 18:06:02 · 254 阅读 · 0 评论 -
进程参数编程
起始字符可以是 :,+,- 或省略省略:=> 出现选项错误时,程序中通过 : 或者?进行处理并给出默认错误提示: => 错误提示开关,程序中通过 : 或者?进行处理 (无默认错误提示)+ => 提前停止开关,遇见操作数时返回 -1,认为选项处理完毕 (后续都是操作数)- => 不重排开关,遇见操作数时,返回 1,optarg 指向操作数字符串组合 => +: or -:进程参数编程main.cint i = 0;int c = 0;原创 2023-06-24 20:23:03 · 307 阅读 · 0 评论 -
初识 Linux 进程
fork() 后,当前进程会创建出和自己一样的子进程,通过 fork() 的返回值可以判断出父进程和子进程,随后,父进程和子进程会同时运行,由于父进程 sleep 100us,所以子进程会先打印,然后父进程再打印。execve 不会创建新的进程,而是将当前进程的进程数据替换为 helloworld.out 的进程数据,并执行,所以执行完 helloworld.out后就结束了,不会打印 end。getpid() 用于获取当前进程的进程号,getppid() 用于获取当前进程的父进程号。原创 2023-06-18 21:56:41 · 836 阅读 · 0 评论 -
深入理解系统调用
用户进程运行在用户模式上,可以通过第三方库和Linux 系统 API (其本质是调用了系统调用)或系统调用进入内核模式,来操作计算机硬件。可以看出 C 标准库的 printf 函数比直接使用系统调用的方式,使用的系统调用次数更多,所花费的时间更长,所以要想我们程序的执行效率高,使用到系统调用的次数越少越好。我们通过 -c 选项来查看使用 C 标准库的 printf 函数和直接使用系统调用的方式执行所有系统调用所花费的时间。系统调用是应用程序 (进程) 是请求模式切换的唯一方式。原创 2023-06-04 17:00:01 · 214 阅读 · 0 评论