这是我的《C 拓展 Python 实战》系列的第五篇,也是这个系列最后一篇。
在之前的文章中,我们的模块需要和 Python 一起编译,这次我们来看看如何使用 setup.py 来随时编译我们的模块。
在此之上,我们再来看看如何结合 CMake 把复杂的 C/C++ 项目打包成 Python Package。
C++对象数据布局(一)——数据对齐的陷阱
C++ Class 对象的数据布局和 C Struct 数据布局遵循同样的原则,按顺序排布并考虑内存对齐的要求。
但是 C++ Class 对象相比于 C Struct 有其创新之处。C++ Class 添加了两个新的 access section,支持在类内声明函数,最重要的是,添加了“继承”的特性。
这其中有什么可怕的陷阱吗?直接公布答案有什么意思,你得自己一步一步趟过去才行。
小心,别中招了!
并发编程(二)—— 多线程
如果我们把进程比作一个工人的话,那线程就是工人的四肢。怎么理解这个比喻呢?
- 工人拥有四肢,进程拥有线程
- 工人干活要依靠手脚来做事,进程干活也是依靠线程来做事
- 工人和工人之间只能通过工头调度或者相同的操作手册(大脑中的知识)来协作,进程和进程之间只能通过操作系统内核调度或者共享内存来协作
- 工人的四肢用工人自己的大脑来协调,进程的线程用进程自己的虚拟内存空间来协作
- 一个工人的四肢的协调效率比多个工人之间的协调效率高,一个进程的线程之间的协作效率比多个进程之间的协作效率要高
并发编程(一)—— 多进程
之前在《基于异常控制流的进程协作》一文中我们从操作系统和硬件的角度简单分析了单核 CPU 上多进程的并发和协作的实现机制。这次我们换个角度,从使用方式的角度来分析并发编程。
文件描述符表 —— 进程的磁盘资源
如果说基于虚拟页表的虚拟内存空间是进程物理内存资源的抽象,那基于文件描述符表的文件系统就是进程磁盘资源的抽象。通过持有文件描述符,进程可以方便地对磁盘上的特定位置(文件)进行读写。
打个不太准确的比方。如果我们把磁盘也看作一个像物理内存一样的字节序列,那磁盘上的文件就像内存中的分页,文件描述符就像 PTE,文件描述符中的 offset 就像 VPN(PPN)。
本文就来解释进程中的文件描述符表的机制。
Win 10 无法发现局域网电脑的解决办法
最近整了一台 Surface Go,想在主力 PC 间实现远程桌面和文件共享。
本以为都 2019 年了这些事情肯定“只需要点一下”就好了,实际上还是有很多坑。这篇文章就记录了 “Win 10 不能发现/连接局域网电脑” 的解决办法,基本上能解决所有网络上提到的 Win 10 联机问题(前提是在局域网)。
- 确保在 “控制面板\网络和 Internet\网络和共享中心\高级共享设置” 勾选了 “启用网络发现” 和 “启用文件和打印机共享”,这是实现任何远程互动的前提
- 如果要使用远程桌面,必须允许远程访问计算机,让 Cortana 找出来“必须允许远程访问计算机”
- 如果要使用文件共享,必须在 “启用或关闭Windows功能” 中启用 SMB,让 Cortana 找出来“启用或关闭Windows功能”
- 让 Cortana 找出“服务”,设置以下服务自动开启:
- PNRP Machine Name Publication Service
- TCP/IP NetBIOS Helper
- Computer Browser(Browser)
- Function Discovery host Provider(FDPHOST)
- Function Discovery Resouce Publication(FDResPub)
- Network Connections(NetMan)
- Upnp Device Host(UpnpHost)
- Peer Name Resolution Protocol (PNRPSvc)
- Peer Networking Grouping (P2PSvc)
- Peer Networking Identity Manager (P2PIMSvc)
- 最后为了省心,干脆重启个电脑吧
基于异常控制流的进程协作
程序是编译出来保存在磁盘上的文件,进程是运行中的程序的实例。操作系统按照程序文件的描述为进程分配了独立的虚拟内存空间,并由 CPU 执行进程的指令。
在理想情况下,CPU 按顺序执行进程的指令。这些有序的指令流叫控制流。虽然控制流在实现分支或者进行调用函数时也会进行跳转,但这种跳转是程序自身有意控制的,属于正常范畴。
不过也有无意发生的跳转:当 CPU 执行完当前指令 I 后,接下来却执行和 I 毫无逻辑关系的 X。而 X 指令,可能是当前进程中的指令,也可能是其它进程中的指令。这种无意的跳转形成的控制流叫异常控制流(Exceptional Controll FLow)。
为什么会出现异常控制流呢?
虚拟内存系统(三)—— 分配和释放 HEAP 内存
.data 内存段、.text 内存段、共享对象内存段在程序加载和链接时就确认了一个不会变的地址范围,而 stack 内存段范围随着函数栈而自动伸缩,不在开发者的掌握之中。如果开发者想要自由地使用一点内存,就要通过 malloc
向 heap 内存申请一段空间来使用。
但 heap 内存空间也不是无限的,如何高效利用 heap 内存空间也就显得很重要了。
高效利用 heap 内存的第一关键点在于回收不再使用的空间,第二点在于分配时合理利用空闲空间。
虚拟内存系统(二)—— 虚拟内存的结构
我们都知道虚拟内存有分区,那都有哪些分区?怎么划分分区的?分区是怎么初始化的?
这篇文章就探讨这些问题。
虚拟内存系统(一)—— 从物理到虚拟
在编译程序的汇编代码的时候,使用了很多内存位置。可是一台计算器只有一个物理内存,编译器怎么确保编译时使用的内存地址不会和其它程序冲突呢?
实际上,每个程序完全不用担心自己使用的内存地址和其它程序产生冲突,因为它们所使用的内存地址都是专属于自己的虚拟地址,在实际寻址的过程中再由操作系统翻译成真正的物理内存地址。
也就是说,虽然物理内存只有一个,但是被划分为多个彼此互不干扰的虚拟内存空间。
那这是如何实现的呢?虚拟内存空间寻址又是如何转换成物理内存空间寻址的呢?