- 博客(275)
- 收藏
- 关注
原创 属性编程与权限编程
struct stat 结构体中的 st_mode 字段记录了文件的访问权限位。文件的物理载体是硬盘,硬盘的最小存储单元是扇区 (每个扇区 512 字节)文件元信息 (创建者、创建日期、文件大小,等) 存储于 inode 区域。设置用户 ID :文件权限中的特殊标志位 (二进制 bit 位)实际用户 ID (EUID) :决定用户对系统资源的访问权限。文件系统以 块 为单位(每个块 8 个扇区) 管理文件数据。如何获取文件的大小,时间戳以及类型等信息?文件的权限可分为 普通权限 和 特殊权限。
2025-02-02 18:50:22
405
原创 深入理解文件描述符
计算机中用于组织、存储和管理文件的数据结构集合管理磁盘或其他存储介质上的空间 (将存储介质分块管理)保证文件数据不被破坏,确保数据的一致性和完整性为用户和应用程序提供了访问和操作文件的标准化接口方便地创建、删除、修改、重命名文件实现对文件的读写以及权限控制等功能。
2025-01-29 22:27:48
426
原创 Linux文件原生操作
Linux 中一切皆文件,那么 Linux 文件是什么?在 Linux 中的文件可以是:传统意义上的有序数据集合,即:文件系统中的物理文件也可以是:设备,管道,内存。。。(Linux 管理的一切对象)
2025-01-29 21:51:13
522
原创 Linux文件基本操作
文件是具有永久存储性,按特定字节顺序组成的命名数据集文件可分为:文本文件,二进制文件文本文件:每个文件存放一个 ASCII 码存储量大,速度慢,便于对字符操作二进制文件:数据按照在内存中的存储形式原样存放存储量小,速度快,便于存放中间结果test3.cint main()exit(1);fclose(fp);return 0;
2025-01-28 12:03:01
939
原创 多线程编程杂谈( 下)
取消点即特殊函数的调用点线程允许取消并且取消类型是延迟取消当接收到取消请求后,执行到特殊函数调用点时,线程退出常用取消点函数在需要退出的 "关键点" 调用此函数,线程返回值为 PTHREAD_CANCELED必须在线程中调用取消状态和取消类型的设置函数除了 pthread_testcancel() 函数, sleep() 函数也是取消点线程接收取消请求后,会执行线程清理函数 (释放资源)进入临界区之前,将取消状态设置为 PTHREAD_CANCEL_DISABLE。
2025-01-27 11:11:47
1028
原创 多线程编程杂谈(上)
该程序创建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
887
原创 多线程局部存储技术
在两个线程中打印 g_global 的地址和值。但在后续的子线程在函数调用的时候,我们需要将指向 ThreadGlobal 类型的指针作为函数的参数传入来区分每个线程专属的全局变量,这边我们使用了宏定义,优化了这个问题。第 67 行,在创建子线程的时候,我们会 malloc 一个 ThreadGlobal 这个结构体,将这个指针传入每个子线程,这样每个子线程都有唯一的变量。第 10 行,我们通过 __thread 关键字来修饰变量 g_global,使得 g_global 变量在每个线程都有一份拷贝。
2024-05-05 16:58:32
320
原创 多线程与信号量简介
第 53 行,get_shared_memory() 函数调用了 shmget() 函数,shmget() 是一个Linux系统调用函数,用于创建一个新的共享内存段(segment)或获取一个已存在的共享内存段。子线程读完以后,信号量 w 的值会加一,主线程才能去写;由于信号量的初始值为 1,所以只能有一个子线程获取到信号量,其它的线程来获取信号量时,发现信号量的值为 0,就会阻塞等待信号量被释放。该程序中使用的两个信号量,信号量 w 和信号量 r,信号量 w 的初始值为 1,信号量 r 的初始值为 0。
2024-05-04 16:40:04
775
原创 线程同步与条件变量
第 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
891
原创 多线程读写锁应用
无论是 "读锁" 还是 "写锁",解锁都是调用 pthread_rwlock_unlock()如果两个线程 "同时" 拿到了 "读锁" 和 "写锁",问:哪个线程先进入临界区执行?读写锁在实现上比互斥量复杂,单纯的 "上锁" 和 "解锁" 操作读写锁相对互斥量低效。因此,针对多线程 "读" & "写" 场景需要更具针对性的解决方案。问题:互斥量可用于多线程 "读" & "写" 共享变量的场景吗?保护临界区时,必须清楚当前需要使用 "读锁" 还是 "写锁"读优先:拿到 "读锁" 的线程优先进入临界区。
2024-02-23 17:22:40
534
1
原创 活锁方案与自旋锁
当超时未能获取目标锁,则让出处理器使用权,线程进入阻塞状态。自旋锁与互斥量类似,在任何时刻,最多只能有一个持有者。轻量级锁定,即:临界区相对短小,自旋锁持有时间非常短。即:线程 获取锁 到 释放锁 的时间内只有一个执行流。自适应锁相对普通互斥量效率更高,相对自旋锁安全性更好。线程一旦获取自旋锁,则不能让出处理器使用权。如果只有一个单核处理器,不建议使用自旋锁。自适应锁先以自旋的方式持续尝试获取目标锁。线程获取互斥量失败后究竟发生了什么?如何设置获取互斥量时的等待时间?一种特殊的互斥量,又名:自适应锁。
2024-02-05 17:28:56
502
原创 多线程互斥量进阶
假设有 三个线程 (A,B,C) 和三个互斥量 (R,S,T),三个线程对互斥量的获取及释放如下,问:是否可能发生死锁?一个线程多次尝试获取同一个互斥量,会发生什么?破坏死锁条件中的任意一个!
2024-02-02 10:29:17
405
原创 排队模型应用案例
定义任务结构体 (CurTask) 模拟顾客 (CurTask 变量表示具体客户)方案:将多个线程预先存储在一个 "池子" 内,当需要线程时直接从 "池子" 取出。使用队列数据结构表示等待队列,队列中存储 CurTask 变量 (顾客排队模拟)各个线程从队列中取任务时是互斥操作 (每次只能一个线程操作队列)如何模拟等待中的顾客 (即:如何模拟待执行的任务)?利用线程池模拟工作窗口,每个线程表示一个工作人员。如何模拟工作窗口 (即:如何模拟工作人员)?线程从队列中取出任务执行 (服务客户模拟)
2024-02-01 16:47:33
382
原创 初识多线程互斥量
这种操作一旦开始,就一直执行到结束,中途不会被打断原子操作可以是一个步骤,也可以是多个步骤的集合原子操作的顺序不可以被打乱,也不可以被切割而只执行其中的一部分原子操作在多 任务/线程 并发时能够保证操作结果的正确性。
2024-02-01 15:43:08
301
原创 线程的连接与分离
pthread_join() 等待的线程必然是 pthread_create() 创建的线程。父进程调用 wait() / waitpid(),为子进程 "收尸" 处理并释放暂留资源。pthread_join() 除了等待线程执行结束,还会释放线程所占用的资源。线程进入分离状态,其它线程无法连接 (不可等待 且 无法获取返回值)线程的分离状态指线程不可能执行连接操作 (并非脱离进程不可控)可连接的线程退出后需要执行连接操作,否则线程资源无法释放。分离状态的线程退出后主动释放系统资源 (常规需求)
2024-02-01 13:52:33
483
原创 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
783
原创 Linux线程API讲解(上)
线程执行流调用 pthread_exit() 函数 (注意:void exit(int status);其它线程对指定线程调用 pthread_cancel() 函数 (不安全)线程入口函数执行了 return 语句,并返回指定值。该函数用于等待指定的线程 (tid) 执行结束。如果指定线程已经执行结束,则函数调用立即返回。如果指定线程必须不可连接,则函数调用失败。参数 retval 用于接收线程 返回值。
2024-01-29 10:37:48
479
原创 深入浅出线程原理
Linux 内核中的基本调度单位为 task_struct,即:内核中以 "任务" 作为调度的基本单位。对于线程来说,pthread_t 类型的标识符 与 pid_t 类型标识有什么不同?每一个线程在内核中都对应一个调度实体,拥有独立的结构体 (task_struct)pid_t pid => 线程标识符 (Thread ID)因此,kill 任意子线程的 pid_t 将导致整个进程结束。进程创建后默认拥有一个线程,即:主线程 (默认执行流)拥有多线程的进程,又被称为线程组 (谁是线程组长?
2024-01-12 14:44:37
974
原创 Linux线程编程初步
线程创建函数:int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);创建 / 销毁 线程花费的时间 < 创建 / 销毁 进程花费的时间。进程:应用程序的一次加载执行 (系统进行资源分配的基本单位)多进程程序共享一段内存 => "机制复杂"进程中的多个线程并行执行,共享进程资源!多线程代码复杂度 > 多进程代码复杂度。线程:进程中的程序执行流。
2024-01-11 19:43:08
448
原创 浅谈进程优先级(下)
换算关系:规范优先级 = MAX_RT_PRIO - 实时优先级 - 1。PRI = 规范优先级 - 40 = 59 - rt_priority。对于实时进程而言,内核模式的优先级与用户模式的优先级并不同。PRI = 规范优先级 - 40 + nice_value。将父进程设置为实时进程,且实时优先级为 99 (调度器)对于实时进程,设置 nice_value 会发生什么?父进程进入循环调度,根据时间片定义改变子进程的调度策略。在优先级不同的时候,先执行优先级高的进程。如何定制实时进程的执行时间?
2024-01-08 17:43:25
705
原创 浅析进程优先级(上)
进程优先级:将处理器资源分配给进程的先后顺序Linux 中每个进程都有相应的优先级 (优先级可能动态改变)进程优先级决定进程 何时执行 和 获得处理器的时间进程优先级通常表现为一个整数值 (数值大小决定优先级高低)
2024-01-08 14:15:14
1062
原创 多核调度实验设计
吞吐量存在理论上限值,进程数量多余处理器数量时,吞吐量只能逼近理论上限值。执行进程数量 处理器数量:延迟增加,吞吐量不变。如何验证处理器,进程数量,吞吐量之间的关系?执行进程数量 = 处理器数量:吞吐量达到顶峰。
2024-01-04 16:27:47
409
原创 多核调度预备知识
ps -- 查看进程运行时数据 (ps au)top -- Linux 整体性能监测工具 (类似任务管理器)sar -- Linux 活动情况报告 (系统性能分析工具)
2024-01-03 17:53:43
1027
原创 初探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
395
原创 信号处理设计模式
线程创建函数:int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);先屏蔽所有信号 (无法递达进程),之后为屏蔽信号创建文件描述符;当时机成熟,通过 read() 系统调用读取未决信号 (主动接收信号)由于给每个信号唯一的标记位置,因此,所有信号转变为不可靠信号;其他线程:首先屏蔽所有可能的信号,之后执行任务代码。每个线程拥有独立的信号屏蔽掩码。
2023-12-26 16:51:38
1594
1
原创 信号优先级与安全性
方案:对目标进程发送 N 次 "无" 序信号,验证信号递达进程的先后次序。不要在信号处理函数中调用不可重入函数 (即:使用了全局变量的函数)对于同一个进程,如果存在两个不同的未决实时信号,那么先处理谁?当信号递达,转而执行信号处理函数时,不可重入的函数不能调用。信号的本质是一种软中断 (中断有优先级,信号也有优先级)不要调用函数中存在临界区的函数 (可能产生竞争导致死锁)不要调用标准 I/O 函数,如:printf() 函数。对于不同的未决实时信号,信号值越小优先级越高。目标:验证信号的优先级。
2023-12-25 10:36:32
931
1
原创 信号可靠性剖析
信号 32 与信号 33 (SIGCANCEL & SIGSETXID) 被NPTL 线程库征用。对于 Linux 内核,信号 32 是最小的可靠信号。不可靠信号的默认处理行为可能不同 (忽略,结束)设置信号队列上限:ulimit -i 1000。信号的可靠性由信号数值决定,与发送方式无关。基于信号发送的进程间通信方式可靠吗?查询信号队列上限:ulimit -i。可靠信号的默认处理行为都是结束进程。信号队列的上限可通过命令设置。不可靠信号 (传统信号)可靠信号 (实时信号)
2023-12-05 19:57:20
1081
原创 信号发送与处理-下
如果希望信号处理之后,被中断的系统调用能够重启,则:可以通过 errno == EINTR 判断重启系统调用。对于执行时间较长的系统调用 (write / read),被信号中断的可能性很大。对于 System V 风格的 signal 函数,会引起信号处理函数的重入。System V 风格的 signal 函数,注册的信号处理是一次性的。系统调用期间,可能收到信号,此时进程必须从系统调用中返回。进程收到信号后,调用由 signal 注册的处理函数。三种注册信号与处理函数的方法有什么区别?
2023-11-08 10:45:36
138
原创 信号发送与处理-上
信号是一种 "软件中断",用来处理异步事件内核发送信号到某个进程,通知进程事件的发送事件可能来自硬件,可能来自用户输入,可能来自除零错误信号是一种类型的进程间通信方式 (一个进程向另一个进程发送信号)A 进程发生事件 T,向 B 进程发送信号,B 进程执行动作响应事件进程可以对接收到的不同信号进行不同响应动作 (信号 => 处理)// 信号处理完毕才返回。
2023-11-07 17:10:43
157
原创 守护进程深度分析
守护进程是系统中执行任务的后台进程不与任何终端相关联 (不接收终端相关的信号)生命周期长,一旦启动,正常情况下不会终止 (直到系统退出)Linux 大多服务器使用守护进程实现 (守护进程名以后缀 d 结尾)
2023-10-22 12:03:14
220
原创 Linux 进程层次分析
/ 设置进程的组标识。// 获取指定进程的组标识。进程组可方便进程管理 (如:同时杀死多个进程,发送一个信号给多个进程)pid_t getpgrp(void);// 获取当前进程的组标识。每个进程都有一个进程组号 (PGID)
2023-09-25 17:27:07
367
原创 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
346
原创 类模板深度剖析
可以指定类模板的特定实现部分类型参数必须显示指定根据类型参数分开实现类模板重定义一个类模板和一个新类 (或者两个类模板)使用的时候需要考虑如何选择的问题特化以统一的方式使用类模板和特化类编译器自动优先选择特化类。
2023-09-19 17:16:38
119
原创 类模板的概念和意义
C++ 中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。 用于说明类中使用的泛指类型 T。如:数组类,链表类,Stack 类,Queue 类,等。类模板外部定义的成员函数需要加上模板 声明。声明的泛指类型 T 可以出现在类模板的任意地方。在 C++ 中是否能够将泛型的思想应用于类?类中数据组织的方式和数据元素的具体类型无关。类模板以相同的方式处理不同类型的数据。类模板不能分开实现在不同的文件中。以相同的方式处理不同的类型。
2023-09-19 16:45:09
150
原创 函数模板的概念和意义
Swap 泛型写法中的 T 不是一个具体的数据类型,而是泛指任意的数据类型。template 关键字用于声明开始进行泛型编程。函数模板是泛型编程在 C++ 中的应用方式之一。C++ 中有没有解决方案集合两种方法的优点?typename 关键字用于声明泛指类型。函数模板是 C++ 中重要的代码复用方式。函数模板能够根据实参对参数类型进行推导。C++ 中有几种交换变量的方法?函数模板支持显示的指定参数类型。不考虑具体数据类型的编程方式。
2023-09-19 14:18:32
150
原创 经典问题解析四
构造函数和析构函数不能发生多态行为,只调用当前类中定义的版本!new / delete 会触发构造函数或者析构函数的调用。dynamic_cast 是与继承相关的类型转换关键字。编译器会检查 dynamic_cast 的使用是否正确。dynamic_cast 是与继承相关的专用转换关键字。dynamic_cast 要求相关的类中必须有虚函数。delete 和 free 的区别是什么?new 和 malloc 的区别是什么?malloc 是由 C 库函数提供的函数。delete 能够触发析构函数的调用。
2023-08-30 15:31:54
120
原创 被遗弃的多重继承
需要进行强制类型转换时,C++ 中推荐使用新式类型转换关键字!与多重继承相关的强制类型转换用 dynamic_cast 完成。与多继承相关的强制类型转换用 dynamic_cast 完成。当架构设计中需要继承时,无法确定使用直接继承还是虚继承!当多重继承关系出现闭合时将产生数据冗余的问题!工程开发中采用 "单继承多接口" 的方式使用多继承。C++ 是否允许一个类继承自多个父类?先继承一个父类,然后实现多个接口。多继承中可以出现多个虚函数表指针。C++ 支持多重继承的编码方式。多重继承的本质与单继承相同!
2023-08-30 14:40:40
122
原创 C++中的抽象类和接口
在现实中需要知道具体的图像类型才能求面积,所以对概念上的 "图形" 求面积是没有意义的!Shape 只是一个概念上的类型,没有具体对象!
2023-08-23 16:02:18
148
原创 C++对象模型分析
class 是一种特殊的 struct在内存中 class 依旧可以看作变量的集合class 和 struct 遵循相同的内存对齐原则class 中的成员函数和成员变量是分开存放的。
2023-08-23 15:29:34
96
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人