背景
最近写c/c++烦了,学了下rust和zig,rust的人体工程学真好,就是写起来不快乐,还是zig好,很快乐 :)
学完基础之后,分析了下将之前写的c++代码重写成zig的可能性,基本上都可以替换,主要是两个方面:
- 变量的生命周期,代码大量使用shared_ptr和unique_ptr,但是还好的是,生命周期基本上是已知的(shared_ptr多线程析构是不安全的,得清楚的知道变量的存活周期);
- NUMA:现代的系统架构都是非对称的,从一个NUMA操作另一个是有性能开销(内存、CPU)。
对第二个问题,之前使用的pthread_setaffinity_np
,但是zig 0.14 的std.c.pthread_xxx
没有这个函数,估计是编译的时候没有开#define _GNU_SOURCE
,所以现在目的很明确,使用操作系统内部的pthread。
方法
- 使用
@cImport
(实测会有问题)
const c = @cImport({
@cInclude("pthread.h");
});
在build.zig
里面增加exe.linkLibC();
,顺便一提,build.zig
文件可以使用zig init
生成。
这里有个坑,如果在cImport
里面定义_GNU_SOURCE
宏,也就是@cDefine("_GNU_SOURCE", "");
,实际不生效,估计是编译器内部处理顺序有问题导致。得放到build.zig
里面:
exe_mod.addCMacro("_GNU_SOURCE", "");
使用这个方法写,会导致CPU_ZERO
和CPU_SET
用不了,报错信息是说解析不了这两个宏定义,看后续编译器版本有无优化了。
- 将之前写的设置affinity封装到c函数中
// file: src/set_affinity.h
#pragma once
#define _GNU_SOURCE
#include <pthread.h>
void set_affinity(pthread_t thread, int cpu);
头文件定义里面只传了一个CPU,实际应该传多个,这里只是简单介绍。
#include "set_affinity.h"
void set_affinity(pthread_t thread, int cpu) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(cpu, &cpuset);
pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
}
注意define要放到pthread.h
的前面,也可以放到build.zig
里面(见方法1)。
后面就简单了,在build.zig里面添加上这个文件就行。
exe_mod.addIncludePath(b.path("src"));
exe_mod.addCSourceFile(.{
.file = b.path("src/set_affinity.c"),
});