lock free在linux中的三种应用场景

并发控制技术详解
本文介绍了三种并发控制技术:自旋锁(SpinLock),允许线程在等待锁时自旋;顺序锁(Seqlock),通过计数器允许多个读操作与写操作并行;RCU(Read-Copy-Update),通过复制数据结构来减少锁的竞争。

 

1.自旋锁:
Spin Lock
当lock操作被阻塞时,线程并不是把自己立即挂起,而是间断性的做自旋(自循环)操作让cpu空转来等待其他线程释放lock

2.顺序锁
Seqlock
允许读写并行。实现原理是通过设定一个计数器,当写操作进行时,将计数器原子的加1,在读操作开始和结束前,都去比较一下计数器的值,如果相等,说明未发生过写操作,如果不相等,则读操作从头进行一次。在写操作频繁的场景下,可能会导致读操作频繁的重复进行

3.RCU
Read-Copy-Update
写操作进行时,复制当前数据结构,申请新内存空间,然后对副本进行修改,将原数组内容复制到new空间中,赋新值,修改完毕后,写者修改原数据结构的指针,使之指向新地址,然后再调用内存屏障,让新值对其他CPU可见,最后释放原结构数据
Linux 环境下,`memset` 函数本身是标准 C 库(glibc)的一部分,通常不会“无法使用”。然而,在某些特定场景下,开发者可能会观察到 `memset` 的行为预期不符,这可能由以下几种原因导致: ### 1. 内存对齐优化问题 某些编译器优化策略可能会导致 `memset` 的行为看起来“无效”。例如,如果编译器检测到 `memset` 后紧接着对内存的写入操作,它可能会优化掉 `memset` 调用以提高性能。这种行为在使用 `-O2` 或更高优化级别时尤为常见。可以通过使用 `volatile` 关键字来防止编译器优化,确保 `memset` 实际执行。 ```c char buffer[1024]; volatile char* ptr = buffer; memset((void*)ptr, 0, sizeof(buffer)); ``` ### 2. 使用不当的参数 `memset` 的原型为 `void *memset(void *s, int c, size_t n);`,其中 `c` 是要设置的值,通常为 0 或 -1。需要注意的是,`c` 是按字节填充的,因此 `memset(s, -1, n)` 实际上会将每个字节设置为 `0xFF`,这在处理整型数组时可能导致意外结果。例如,`int arr[10]; memset(arr, -1, sizeof(arr));` 会将每个 `int` 设置为 `0xFFFFFFFF`,这在有符号整数中表示 `-1`,但在某些平台上可能不被期望。 ### 3. 内存访问权限问题 如果尝试对只读内存区域(如常量字符串或某些受保护的内存映射区域)使用 `memset`,将导致段错误(Segmentation Fault)。确保操作的内存区域是可写的,可以通过 `malloc` 或 `mmap` 正确分配,并检查内存指针是否为 `NULL`。 ```c char* buffer = malloc(1024); if (buffer != NULL) { memset(buffer, 0, 1024); free(buffer); } ``` ### 4. 多线程环境下的竞争条件 在多线程程序中,若多个线程同时访问并修改同一块内存区域,而未采取适当的同步机制(如互斥锁),可能导致 `memset` 的效果被其他线程的操作覆盖。可以使用 `pthread_mutex_lock` 和 `pthread_mutex_unlock` 来保护共享内存的访问。 ```c pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; char shared_buffer[1024]; void reset_buffer() { pthread_mutex_lock(&mutex); memset(shared_buffer, 0, sizeof(shared_buffer)); pthread_mutex_unlock(&mutex); } ``` ### 5. 使用 `memset` 清除敏感数据的安全问题 `memset` 并不能保证在优化后的代码中真正清除内存,特别是在涉及敏感数据(如密码)时。可以使用 `explicit_bzero` 或 `memzero` 等函数来确保数据被可靠清除,避免被恶意恢复。 ```c #include <string.h> char password[128]; // ... 使用 password ... explicit_bzero(password, sizeof(password)); // 安全清除密码 ``` ### 6. 内存泄漏或越界访问 如果 `memset` 操作的内存区域未正确分配或存在越界访问,可能导致不可预测的行为,包括程序崩溃或数据损坏。确保 `memset` 的第三个参数 `n` 不超过分配的内存大小,并且指针 `s` 是有效的。 ```c char* buffer = malloc(100); if (buffer != NULL) { memset(buffer, 0, 100); // 确保 n 不超过分配的大小 free(buffer); } ``` ### 7. 使用 `memset` 初始化结构体 当使用 `memset` 初始化结构体时,特别是包含指针成员的结构体,需格外小心。`memset` 会将所有成员初始化为 0,这可能导致指针成员被设置为 `NULL`,而某些结构体的设计可能依赖于指针成员的初始值。 ```c typedef struct { int id; char* name; } User; User user; memset(&user, 0, sizeof(User)); // name 被初始化为 NULL ``` ### 8. 内存映射文件的处理 对于通过 `mmap` 映射的文件,`memset` 操作可能不会立即反映在磁盘文件上,除非调用 `msync` 强制同步内存磁盘内容。 ```c char* mapped = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); if (mapped != MAP_FAILED) { memset(mapped, 0, length); msync(mapped, length, MS_SYNC); // 确保数据写回磁盘 munmap(mapped, length); } ``` ### 9. 内核模块或驱动开发中的限制 在内核空间开发中,`memset` 可能不可用或行为受限,因为内核提供了自己的内存操作函数(如 `memset_io`)。在这种情况下,应使用内核提供的替代函数。 ```c #include <linux/io.h> void __iomem* addr = ioremap(phys_addr, size); writel(0, addr); // 替代 memset_io(addr, 0, size) ``` ### 10. 特定平台或编译器的兼容性问题 某些嵌入式平台或非标准编译器可能对 `memset` 的实现存在差异,导致其行为不符合预期。查阅目标平台的文档,确认 `memset` 的可用性和行为特性。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值