PostgreSQL中获取LWLock的正确方式及两种方法的区别与适用场景
PostgreSQL 11.4中两种LWLock获取方式的区别与适用场景
第一种方式:命名Tranche预分配批量锁
通过RequestNamedLWLockTranche和GetNamedLWLockTranche组合实现:
extern void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks); extern LWLockPadded *GetNamedLWLockTranche(const char *tranche_name);
核心流程
- 注册锁组:调用
RequestNamedLWLockTranche在数据库启动阶段注册一个命名锁组(tranche),指定该组内锁的总数,系统会自动在MainLWLockArray中预分配对应数量的LWLockPadded结构。 - 获取锁组:通过
GetNamedLWLockTranche传入锁组名称,直接拿到整个锁组的数组,后续通过数组下标即可访问具体锁实例。
特点
- 固定数量:锁的总数在初始化阶段确定,运行时无法动态调整。
- 内存自动管理:锁的内存由PostgreSQL统一分配、维护,无需手动处理内存分配逻辑。
- 可读性高:通过名称直接关联锁组,代码逻辑直观易懂。
适用场景
- 适用于生命周期贯穿数据库进程、数量固定的系统级锁,比如WAL写入锁、缓冲池页面锁这类内置子系统的锁。
- 适合在数据库启动时就能明确锁数量的场景,避免运行时动态分配的额外开销。
第二种方式:动态自定义锁
通过LWLockNewTrancheId、LWLockRegisterTranche和LWLockInitialize组合实现:
extern int LWLockNewTrancheId(void); extern void LWLockRegisterTranche(int tranche_id, const char *tranche_name); extern void LWLockInitialize(LWLock *lock, int tranche_id);
核心流程
- 获取唯一ID:调用
LWLockNewTrancheId拿到一个全局唯一的tranche ID,用于标识一组锁。 - 注册锁组名称:通过
LWLockRegisterTranche将tranche ID与名称绑定,方便监控、调试时识别锁组。 - 初始化锁实例:调用
LWLockInitialize初始化具体的LWLock实例(该实例可放置在MainLWLockArray或自定义共享内存区域),并关联到之前获取的tranche ID。
特点
- 动态灵活:锁的数量、位置可在运行时动态决定,无需提前预分配。
- 手动内存管理:需要自行负责
LWLock结构的内存分配(比如从共享内存中预留空间)。 - 嵌入式适配:可以将锁直接嵌入到自定义共享数据结构中,而非统一放在预分配的锁组数组里。
适用场景
- 适用于锁数量不确定、需要运行时动态创建的场景,比如用户扩展模块中的自定义共享资源锁。
- 适合将锁与特定数据结构绑定的场景,比如共享哈希表的每个桶自带的锁,需随数据结构动态初始化。
核心对比
| 维度 | 第一种方式(命名预分配) | 第二种方式(动态自定义) |
|---|---|---|
| 锁数量灵活性 | 固定,初始化阶段确定 | 动态,运行时可调整 |
| 内存管理 | 系统自动分配维护 | 手动分配和初始化 |
| 使用复杂度 | 低,直接通过名称获取锁组 | 高,需自行管理锁实例 |
| 典型适用场景 | 系统级固定数量锁 | 自定义动态/嵌入式锁 |
内容的提问来源于stack exchange,提问作者Sri
相关产品推荐
相关产品推荐

