@bit::Shadow
✧(≖ ◡ ≖✿
目录
[" \ "必须加?](#“ \ ”必须加?)
[System V前瞻](#System V前瞻)
[链接🔗System V共享内存内核级详解下篇](#链接🔗System V共享内存内核级详解下篇)
[System V消息队列(queue)](#System V消息队列(queue))
[System V信号量(Semaphoes)](#System V信号量(Semaphoes))
[System V信号量接口](#System V信号量接口)
*C中的FILE与PCB的关系?
| 概念 | 所在位置 | 管理者 |
|---|---|---|
FILE 结构体 |
用户空间 | C 标准库(glibc) |
file 结构体(内核) |
内核空间 | 内核 |
| 文件描述符表 | PCB 内(内核空间) | 内核 |
子进程初创时图解
子进程初创:
部分独立,部分指向原内容区。

命名管道
原理:利用路径的唯一性,创建"伪文件"(命名管道)标识,来关联不同进程,实现进程间通信。
命名管道是一个特殊的文件,以权限符"p"标识,由于管道通信数据先进先出的性质常以FIFO来指示命名管道。
mkfifo()创建
指令:
bash
mkfifo fifo
代码:
cpp
int mkfifo(const char* pathname, mode_t mode);
pathname:要创建文件的路径+名字。
mode:权限设置。 0666
返回值:
-1:失败,错误码被设置
0:正常创建。

unlink()删除管道文件
指令:
bash
unlink #管道文件名
代码:
cpp
int unlink(const char* pathname);
命名管道分作读取端与写端,当读取端打开写入端没有打开时或写端打开读端没有打开时均会阻塞。阻塞在open()或read()
☆☆☆命名管道关闭的正确顺序:
cpp
close(fd); // 1. 先关闭文件描述符 不再占用此文件
unlink("fifo"); // 2. 再删除文件 删除目录项 文件引用计数-1到0时删除
模拟服务端与客户端交互:
实现服务端(Server)到客户端(Client)的信息发送"I'm father",客户端读取输出。
服务端
1.创建命名管道fifo
2.打开管道并写入
3.关闭fd删除命名管道
cpp
//Server.cc
int Sever() {
int n = mkfifo("fifo", 0666);
if(n == -1)
{
perror("错误");
exit(1);
}
// 打开 写入"I'm father"
int fd = open("fifo", O_WRONLY);
if(fd == -1)
{
perror("open\n");
exit(1);
}
printf("打开成功准备写入");
// 写入
std::string s = "I'm father";
write(fd, s.c_str(), s.size());
printf("写入完毕\n");
// 关闭
close(fd);
//删除
unlink("fifo");
return 0;
}
客户端
1.打开、读取。
2.输出关闭。
cpp
//Client.cc
int Client() {
//打开
int fd = open("fifo", O_RDONLY);
if(fd == -1)
{
perror("open fail");
exit(1);
}
// 读取
char s[64] = {0};
int n = read(fd, s, 63);
if(n == -1)
{
perror("read failed");
exit(1);
}
// 输出
printf("客户端读取结果:%s\n", s);
// 关闭
close(fd);
return 0;
}
MP4效果演示
服务端写入信息,客户端读取
注意点:
1.mkfifo时若已经存在则失败。
2.读端open时未创建则失败。
3.写后要关闭+删除。
ERR_EXIT异常退出宏定义
由于以后及及现在的检验原理激增所以定义此宏就十分有必要。
使用do { ...... }while(0)循环的目的是使此宏得以适应各种逻辑语句内。像循环语句,条件语句等等。
cpp
#define ERR_EXIT(str) \
do\
{\
perror(m);\
exit(EXIT_FAILURE);\
}while(0)
" \ "必须加?
是的因为宏是全替换。
匿名管道与命名管道的总结
匿名管道通过int pipe(int fds2);创建一fds0与fds1分别作管道的读端和写端 并分别占用该进程接下来的两个文件描述符fd,配合fork()使用以分支父子进程,若要实现单向通信,可以父进程读端关闭子进程写端 关闭。匿名管道是文件流无文件本身与磁盘分隔。
命名管道通过int mkfifo(const char* pathname, mode_t mode);实现具有名字"伪文件"管道的创建,其打破了"相邻进程间通信"的限制,操作完全类似于文件操作但unlink(int fd);删除目录项。
System V前瞻
System V(通常读作 "System Five")是 Unix 操作系统历史上最重要的法定版本之一,由 AT&T 贝尔实验室于 1983 年首次发布。它不仅奠定了现代商业 Unix 的基础,其许多设计理念和机制至今仍深深影响着 Linux 和 macOS 等现代操作系统。
System V信号量(Semaphoes):用于多个进程对共享资源的访问,解决同步与互斥问题。++仅作简要介绍。++
System V消息队列:允许进程以消息链表(队列)的形式异步发送和接受数据块。++仅作简要介绍。++
链接🔗System V共享内存内核级详解下篇
System V消息队列(queue)

System V信号量(Semaphoes)
解决System V中进程间数据安全问题。
信号量介绍:
"信号量"又称"信号灯",是描述对资源(内存、共享内存)预订情况的量,若可用资源已经耗尽,则申请(再次预订)会失败并阻塞挂起。
"资源耗尽"的信号灯依据------PV机制(荷兰语:Proberen,尝试/申请 ,Verhogen,增加/释放)。
PV机制(原子性"二态性"):
例原本int sem = 16;
申请维护sem--,原子操作 P操作。
退出归还sem++,原子操作 V操作。
例,若sem = 1;仅有"1"和"0"两种状态,称为"二元信号量"。
信号量相关术语
临界资源:被保护起来的共享资源。
临界区:每个进程中访问临界资源的那段"代码"。
非临界区:不涉及共享资源(如:全局变量、共享内存、硬件设备等)操作的代码区域
互斥:一种制约关系。当一个进程进入临界区使用资源时 ,其他资源必须等待,直到该进程退出临界区。(银行自用ATM机)
临界区与非临界区的对比
| 特性 | 临界区 (Critical Section) | 非临界区 (Non-critical Section) |
| 资源访问 | 访问共享资源(如修改公共变量、写日志文件) | 只访问局部变量或进行独立计算 |
| 并发冲突 | 多个线程同时进入会导致**数据竞争(Data Race)**或死锁 | 多个线程同时执行互不影响,完全安全 |
| 同步控制 | 必须加锁(如 Mutex、Semaphore)限制访问 | 无需任何锁,线程可以并发现行 |
| 执行时间 | 应当越短越好(减少其他线程的等待时间) | 往往包含大量的业务逻辑、计算或I/O |
|---|
"锁"区分临界区非临界区图解:

System V信号量接口
创建 int semget(key_t key, int nsems, int semflg);
控制 int sectl(int semid, int semnum, int cmd,......);
int semop(int semid ,struct sembuf* sops, size_t nsops);
感谢支持,持续更新
欢迎关注
