Skip to content
/ ipcator Public

Allocator of Inter-Process Shared Memory Resources. 进程间共享内存资源的分配器, POSIX-compatible.

License

Notifications You must be signed in to change notification settings

shynur/ipcator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Getting Started

一个简单的示例, 在 reader 进程中执行 writer 进程里的函数 (该示例未必能成功执行, 因为可能运行于容器 (参见 docker --tmpfs 参数) 等权限受限的环境中):

#include "ipcator.hpp"
using namespace literals;
int shared_fn(int n) { return 2 * n + 1; } // 要传递的函数.
int main(int, const char *const av[]) {
auto shm_allocator = Monotonic_ShM_Buffer/* 或 ShM_Pool<false> 或 ShM_Pool<true> */{};
const auto size_fn = std::stoul([&] { const auto p = popen(("echo print\\(0x`nm -SC "s + av[0] + " | grep ' shared_fn(int)$' - | awk -F' ' '{print $2}'`\\) | python3").c_str(), "r"); char buf[4]; fgets(buf, sizeof buf, p); return std::string{buf}; }());
const auto block = (char *)shm_allocator.allocate(size_fn); // 向 buffer 申请内存块.
for (const auto i : std::views::iota(0u, size_fn))
block[i] = ((char *)shared_fn)[i]; // 向内存块写入数据.
// 查找 block 所在的 POSIX shared memory:
const auto& target_shm = shm_allocator.upstream_resource()->find_arena(block);
// block 在 POSIX shared memory 中的 偏移量:
const auto offset = (char *)block - std::data(target_shm);
// 事先约定的共享内存, 用来存放消息的位置区域和偏移量:
const auto descriptor = "/ipcator.msg_descriptor"_shm[32];
(std::pair<std::array<char, 24>, std::size_t>&)descriptor[0] = {
*(std::array<char, 24> *)target_shm.get_name().c_str(), offset
};
std::this_thread::sleep_for(1s); // 等待 reader 获取消息.
}
#include "ipcator.hpp"
ShM_Reader rd;
int main() {
std::this_thread::sleep_for(0.3s); // 等 writer 先创建好消息.
const auto [name, offset] = *rd.template read<
std::pair<std::array<char, 24>, std::size_t>
>("/ipcator.msg_descriptor", 0);
const auto mul2_add1 = rd.template read<int(int)>(name.data(), offset);
std::this_thread::sleep_for(1.3s); // 这时 writer 进程已经退出了, 但我们仍能读取消息:
std::cout << "\n[[[ 42 x 2 + 1 = " << (*mul2_add1)(42) << " ]]]\n\n\n";
}

你可自己手动编译执行; 也可根据 测试双进程间的通信 的提示, 将以上两段代码分别填到 src 目录下的 ipc-*.cpp 文件中, 再在仓库目录用 NDEBUG=1 CXX=g++-10 ISOCPP=2a make ipc (自己调整 CXXISOCPP) 自动执行.

功能

提供 POSIX-compatible 的共享内存分配器与读取器.

执行 make doc 以生成文档 (在 docs/html/).

下载

git clone -b master --single-branch --recurse-submodule https://github.com/shynur/ipcator.git
(cd ipcator
 git checkout `git tag --sort=-creatordate | grep [0-9]\$ - | head -n 1`)

工具链要求

  • Bash, awk, sed, grep.

  • Doxygen, Graphviz.

  • g++-10 (上至 g++-15), 或 clang++-16 (上至 clang++-21) 1.

  • 直接执行 make print-vars, 不飘红就行; 否则, 根据提示设置正确的 编译器 和 C++ 标准.
    例如, 在我的机器上有报错: g++: error: unrecognized command line option ‘-std=c++26’; did you mean ‘-std=c++2a’?, 说明编译器 (g++-9) 太旧导致有些选项无法识别, 而 C++ 标准太新. 重新执行

    CXX=g++-10 ISOCPP=2a make print-vars

依赖项

IPCator 抗拒使用第三方库, 除了 同样是 mono-header-only 的库 和 某些标准库的前身:

<format> ➡️ fmt/format.h

C++20 开始提供 <format>, 但 g++-10 -std=c++2a 实际只支持部分新特性.

通过执行 make print-vars | grep LIBS - 查看 LIBS 变量中是否包含 fmt. 如果, 说明本地缺少 <format> 库, 需要额外执行:

git submodule init lib/fmt
git submodule update lib/fmt

后续的 make 会在必要时编译生成 libfmt.a.

试运行

在单个进程中测试

make test
#
NDEBUG=1 make test  # 更好的性能, 更少的日志

测试双进程间的通信

将代码填入 src/ipc-writer.cppsrc/ipc-reader.cpp, 然后

make ipc
#
NDEBUG=1 make ipc

就能看到结果.

兼容性测试

默认使用 g++ 编译, 标准为 C++26. 但是可以:

export CXX=clang++-20  # 替换编译器为 LLVM Clang
export ISOCPP=2a  # 使用 C++2a
export NDEBUG=1  # 如果不使用 GCC, 那么这一步是必须的!
# 这 ^^^^^^^^^^^ 会排除许多独属 GCC 而 Clang 无法识别的 debug 选项.
make clean  # 删除用原来的编译器生成的链接库 e.g. `libfmt`.
make test ipc

用法

#define IPCATOR_NAMESPACE some_namespace #include "ipcator.hpp"

如果 IPCATOR_NAMESPACE 宏 未定义, 则 API 置于 global namespace.

API 使用示例

详见 include/tester.hpp.

注意事项

降级 $ISOCPP 编译时, 无法实现所有语义 (例如封装性与 const 方法的重载).
特别是, 形如 异质查找 (P0919R3) 等新的 STL 算法可能会被手工编写的代码代替, 严重降低性能.


Footnotes

  1. 指开源版 Clang, 而不是 Apple Clang.

About

Allocator of Inter-Process Shared Memory Resources. 进程间共享内存资源的分配器, POSIX-compatible.

Topics

Resources

License

Stars

Watchers

Forks