顺序锁(seqlock)不能安全地保护指针类型数据,主要是因为它的读者是无锁读取的,无法保证在读取过程中指针指向的内容不会被写者修改或释放,从而导致野指针、数据不一致或崩溃。
顺序锁是一种乐观锁,适用于“读多写少”的场景:
写者加锁并更新版本号(通常是一个整数)。
读者不加锁,读取数据前后检查版本号是否一致。
如果版本号在读前后不一致,说明有写入发生,读者需要重试。
写者可能在更新过程中释放或替换指针指向的结构体。
读者在无锁状态下访问该指针,可能访问已释放或未初始化的内存。
即使版本号一致,读者可能读取到部分更新前、部分更新后的字段,导致数据不一致。
顺序锁只能保证版本号一致性,不能保证指针指向的数据在读者读取过程中不被修改。
struct my_data { int a; int b; }; struct my_data *shared_ptr; seqlock_t my_seqlock; reader() { unsigned seq; struct my_data *local; do { seq = read_seqbegin(&my_seqlock); local = shared_ptr; // 读指针 int a = local->a; // 访问指针内容 int b = local->b; } while (read_seqretry(&my_seqlock, seq)); }
如果shared_ptr在写者中被替换或释放,读者可能访问非法内存,导致崩溃。
顺序锁适合保护标量数据(如整数、时间戳、计数器等)。
若要保护指针类型数据,应使用:
RCU(Read-Copy-Update):适合保护指针和复杂结构体,读者无锁访问,写者延迟释放。
读写锁(rwlock):读者加共享锁,写者加独占锁,确保一致性。
特性 | 顺序锁 | RCU / 读写锁 |
---|---|---|
是否适合保护指针 | ❌ 不适合 | ✅ 适合 |
读者是否加锁 | ❌ 无锁读取 | RCU:无锁;rwlock:加锁 |
是否能防止释放指针内存 | ❌ 无法防止 | ✅ RCU 延迟释放或加锁保护 |
推荐使用场景 | 标量数据,高读低写 | 指针数据、复杂结构体 |
如果你正在设计内核模块或驱动,我可以帮你判断是否该用顺序锁、RCU 或其他同步机制,并给出代码模板!