找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 202|回复: 14

浅谈 POSIX 与操作系统的关系

[复制链接]

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24239 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
发表于 2024-3-30 15:59:46 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×

POSIX 这个东西,它是个标准,但它既不是 Unix 标准,也不是 Linux 标准。POSIX 就是 POSIX,可以算是“一种操作系统标准”,操作系统可以参考这个标准去实现需要的功能。

Linux/Unix 实现了部分/全部 POSIX 标准的层,而 Windows 也提供了部分 POSIX 函数。mingw 的主要贡献之一就是给 Windows 提供更完整的 POSIX 功能(有,但是不多)。

举个例子:我有个国产单片机 F1C200S。我有它的裸机开发板。它裸机里面有个内核层,这个内核层会检测你是不是“烧录/下载”模式,是的话,进行串口通信(串口通信就是一条线收 + 一条线发 + 一条线接地,钦定频率,比如我就用 115200 Hz,每个字节有个“开始 bit”+ 中间的 8 个 bit + “结尾 bit”,算下来每秒钟 11520 字节,相当于 11.25KB 每秒的传输速度。接收方也按照 115200 这个速度来检测这条线的电压高低,电压拉低表示“开始 bit”,然后连续接受 8 个 bit 后,电压升高表示“结束 bit”,以此传输每个字节)。裸机的内核层以此来实现从电脑 PC USB 串口上下载单片机的程序代码。

然后,这个单片机的程序代码是我编写的,我可以在这个基础上,按照 POSIX 的标准来提供函数,并封装函数;比如我的 stdout/stderr 接的是“串口出”,stdin 接的是“串口入”,然后我串口频率写死了是 115200 Hz;我山寨一套 C 语言标准库函数(比如 C11),让所有 printf()(本质上是 fprintf(stdout, "xxx",...))的调用写出到“串口出”,然后“串口入”一旦有数据,我就写入到一个预先保留的 buffer 里面去,所有的 fgetc(stdin) 读取的都是这个 buffer 里面的内容。

再在这个基础上,对 fopen 的文件路径之类的做魔改,比如我就规定 /dev/stdout 是写串口出的。

类似的,有 musl 这样的东西提供类似的功能,你只需要实现 int __io_getchar()void __io_putchar() 的函数行为,你就可以在你的程序代码里调用 printf() 或者使用其它的函数对 stdin/stdout 进行读写操作。

那这样一来,我就成功山寨了 Unix + 部分 POSIX 函数。只是,对于国产芯片,现在最大的问题是它依赖 gcc 而且依赖特定版本的 gcc 而且依赖 gcc 的 bug。

一旦发售 + 编译成功出 bootloader 便不再维护,然后你在例如 gcc 的版本是 gcc12 的年代去编译古代的国产芯片,你就会碰壁,因为 gcc12 修复了 gcc9 的 bug(gcc9 不能正确处理 C 语言的 static 关键字,后续版本的 gcc 新增了 -fcommon 来允许你在多个不同的 .c 文件中使用 static 关键字声明相同名字类型的未初始化全局变量),导致你无论如何也编译不出你的 bootloader 或者 buildroot。你必须想办法获取对应的 gcc 版本编译器,能直接编译/交叉编译出你需要的 bin,来编译你的源码库。

顺带一提 buildroot 基本就是山寨版 Linux 的极简版,稍微改造改造比如做个 X Server 然后走 SPI 串口输出屏显内容到一个液晶屏芯片比如 ILI9341 你就能做个带桌面的 Linux 掌上电脑。

那么这样一来,任何提供了源码的、走 X Client 协议的、能在你环境下编译为你的单片机的机器码的库(github 库)你就都支持了。

那你就可以声称:“我是小凯,我创造了凯OS(chaos)”

回复

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2024-4-7 19:55:13 | 显示全部楼层
简而言之,POSIX是“操作系统的规范/标准”而不是“操作系统”。但实际上,几乎没有主流的操作系统【完全】实现这个规范/标准。

为了兼容性,我的联网程序几乎都只使用POSIX定义的SOCKET函数。

我写了一个在WINDOWS驱动层联网的库,封装了TDI/WSK函数,几乎完整实现了全套的POSIX定义的SOCKET函数。
回复 赞! 靠!

使用道具 举报

9

主题

177

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8675 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2024-4-8 18:08:50 | 显示全部楼层
美俪女神 发表于 2024-4-7 19:55
简而言之,POSIX是“操作系统的规范/标准”而不是“操作系统”。但实际上,几乎没有主流的操作系统【完全】 ...

但POSIX的socket函数全是阻塞模式,用起来不是很蛋疼吗?

点评

俺就喜欢阻塞模式的SOCKET。  发表于 2024-4-8 19:51
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2786

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2166 个
贡献
206 次
宅之契约
0 份
在线时间
481 小时
注册时间
2016-7-12
发表于 2024-4-8 22:48:56 | 显示全部楼层
YY菌 发表于 2024-4-8 18:08
但POSIX的socket函数全是阻塞模式,用起来不是很蛋疼吗?

阻塞模式写起来逻辑省心,不依赖多线程的非阻塞往往依赖硬件或者频繁切换,性能损耗还是比较严重的
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2024-4-9 08:27:49 | 显示全部楼层
AyalaRs 发表于 2024-4-8 22:48
阻塞模式写起来逻辑省心,不依赖多线程的非阻塞往往依赖硬件或者频繁切换,性能损耗还是比较严重的 ...


话说通讯线程卡死也不怕,只需要开一个监控线程,一旦发现通讯线程没有心跳了,一套KeInsertQueueApc(PsTerminateSystemThread) + KeAlertResumeThread/KeForceResumeThread组合拳下来,再重新PsCreateSystemThread就行了。
回复 赞! 靠!

使用道具 举报

9

主题

177

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8675 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2024-4-9 09:24:10 | 显示全部楼层
AyalaRs 发表于 2024-4-8 22:48
阻塞模式写起来逻辑省心,不依赖多线程的非阻塞往往依赖硬件或者频繁切换,性能损耗还是比较严重的 ...

但多线程+阻塞的性能损耗不是更严重吗?
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2786

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2166 个
贡献
206 次
宅之契约
0 份
在线时间
481 小时
注册时间
2016-7-12
发表于 2024-4-9 14:24:48 | 显示全部楼层
YY菌 发表于 2024-4-9 09:24
但多线程+阻塞的性能损耗不是更严重吗?

阻塞是性能利用率低,本身性能损耗也低,加上多线程之后是否损耗更严重,取决于多线程本身设计
回复 赞! 靠!

使用道具 举报

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24239 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
 楼主| 发表于 2024-4-11 15:41:26 | 显示全部楼层
YY菌 发表于 2024-4-8 18:08
但POSIX的socket函数全是阻塞模式,用起来不是很蛋疼吗?

用好 select() / poll() 就行了,另外其实非阻塞的效率是非常低的,它在大多数情况下与操作系统本身的设计相悖(它需要轮询),而网络通讯这块,操作系统往往更喜欢设备发出中断唤醒操作系统去处理,因此实际上阻塞模型 + select() / poll() 的效率比非阻塞模型的效率高。

回复 赞! 靠!

使用道具 举报

9

主题

177

回帖

1万

积分

用户组: 真·技术宅

UID
4293
精华
6
威望
441 点
宅币
8675 个
贡献
850 次
宅之契约
0 份
在线时间
338 小时
注册时间
2018-9-19
发表于 2024-4-12 08:44:24 | 显示全部楼层
0xAA55 发表于 2024-4-11 15:41
[md]用好 `select()` / `poll()` 就行了,另外其实非阻塞的效率是非常低的,它在大多数情况下与操作系统 ...

select和poll的效率也不行,还是得要epoll和IOCP这种事件机制的才行。
回复 赞! 靠!

使用道具 举报

55

主题

275

回帖

9352

积分

用户组: 管理员

UID
77
精华
16
威望
237 点
宅币
8217 个
贡献
251 次
宅之契约
0 份
在线时间
254 小时
注册时间
2014-2-22
发表于 2024-4-13 06:25:02 | 显示全部楼层
0xAA55 发表于 2024-4-11 15:41
[md]用好 `select()` / `poll()` 就行了,另外其实非阻塞的效率是非常低的,它在大多数情况下与操作系统 ...

poll是个啥玩意?WINDOWS的WINSOCK2好像没有实现这个函数。

点评

Windows 虽然没有 poll,但是有 WSAPoll。😂  发表于 2024-4-15 09:17
回复 赞! 靠!

使用道具 举报

30

主题

211

回帖

2786

积分

用户组: 版主

UID
1821
精华
7
威望
69 点
宅币
2166 个
贡献
206 次
宅之契约
0 份
在线时间
481 小时
注册时间
2016-7-12
发表于 2024-4-13 20:54:23 | 显示全部楼层
本帖最后由 AyalaRs 于 2024-4-13 20:59 编辑
YY菌 发表于 2024-4-12 08:44
select和poll的效率也不行,还是得要epoll和IOCP这种事件机制的才行。


阻塞和非阻塞的底层都是需要基于事件或信号的,系统提供的接口自身会实现一个默认的回调,回调处理方式一般是线性的,然后交给应用层一个简易接口,如果系统直接把这个回调接口提交给应用层自己处理效率就会变得很高,不过交给应用层处理之前还需要做一个防护性的包装还有调度处理
分别调用不同回调处理函数和调用同一个回调再调用处理函数,两种方式本身也会出现性能博弈,通常前者效率高,但是占用资源也要多,这个占用是先发性的,通常能充分发挥硬件多任务处理性能
后者本身存在一个问题,就是回调函数本身是否超过线程处理能力,如果没超过,那么性能占用和效率上就完全超过前者,否则就会陷入瓶颈
回复 赞! 靠!

使用道具 举报

65

主题

117

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8304 个
贡献
1094 次
宅之契约
0 份
在线时间
2070 小时
注册时间
2015-8-15
发表于 2024-4-14 23:18:37 | 显示全部楼层
美俪女神 发表于 2024-4-13 06:25
poll是个啥玩意?WINDOWS的WINSOCK2好像没有实现这个函数。

https://learn.microsoft.com/en-u ... nf-winsock2-wsapoll
回复 赞! 靠!

使用道具 举报

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24239 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
 楼主| 发表于 2024-4-15 16:19:47 | 显示全部楼层
美俪女神 发表于 2024-4-13 06:25
poll是个啥玩意?WINDOWS的WINSOCK2好像没有实现这个函数。

poll()select() 爽,作用相同,但 poll() 效率更高。

回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-24 04:20 , Processed in 0.040785 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表