目录1.STL、智能指针与线程安全STL容器默认不是线程安全的智能指针线程安全2.读者写者问题背景读写锁核心特性321原则优先级策略POSIX读写锁接口读写锁示例设置写者优先示例1.STL、智能指针与线程安全STL容器默认不是线程安全的多线程环境下需要调用者自行保证线程安全常见方案使用外部锁如std::mutex保护容器操作智能指针线程安全1.unique_ptr独享所有权线程安全特性不涉及线程安全问题原因只在当前代码块范围内生效独占资源所有权不存在多个线程共享的情况2. shared_ptr共享所有权两部分需要区分对待组成部分线程安全性说明引用计数线程安全标准库基于原子操作(CAS)实现保证高效原子操作管理的资源不保证安全智能指针只负责管理资源生命周期不保护资源内容的并发访问关键理解引用计数的增减是原子操作多个线程同时操作shared_ptr不会导致计数错乱但通过shared_ptr访问的资源对象本身需要调用者自行加锁保护2.读者写者问题背景多读少写场景某些公共数据修改机会少但读取查找操作频繁且耗时。传统互斥锁会严重降低并发效率需要专门机制处理读写锁核心特性特性说明写独占写者加锁时其他读者和写者都不能访问读共享多个读者可以同时加锁读取数据优先级可设置读者优先或写者优先321原则维度内容说明3种关系写写互斥多个写者不能同时写写读互斥、同步写和读不能同时进行且需数据同步读读共享多个读者可以同时读2种角色读者、写者两类线程操作数据1个交易场所共享数据数据交换的内存区域优先级策略策略特点问题适用场景读者优先默认读者持续进入时写者被阻塞写者可能饥饿读极多、写可延迟写者优先写者到达后阻塞后续读者读者可能饥饿写操作需及时响应读者优先策略下只要存在任何读者正在读取数据后续到达的读者可以立即获得读锁继续读取而写者必须等待所有读者释放锁后才能写入。这种策略适合读操作极其频繁、写操作可以延迟的场景但可能导致写者饥饿——当读者持续不断地到来时写者可能永远无法获得写锁写者优先策略下一旦有写者到达并等待写锁后续新到达的读者将被阻塞不能插队读取直到等待的写者完成写入操作。这种策略确保写操作能及时执行适合需要数据及时更新的场景但可能造成读者饥饿——如果写者频繁出现读者可能长时间无法获取读锁。POSIX读写锁接口// 设置优先级 int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref); /* pref取值 PTHREAD_RWLOCK_PREFER_READER_NP - 读者优先默认 PTHREAD_RWLOCK_PREFER_WRITER_NP - 写者优先有BUG实际同读者优先 PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP - 写者优先写者不可递归 */ // 初始化和销毁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); // 加锁和解锁 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); // 读锁 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); // 写锁 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); // 解锁读写锁示例#include stdio.h #include pthread.h #include unistd.h #include stdlib.h // 共享数据 int shared_data 0; // 读写锁 pthread_rwlock_t rwlock; // 读者线程 void* reader(void* arg) { int id *(int*)arg; while (1) { // 加读锁 pthread_rwlock_rdlock(rwlock); printf(读者 %d 读取数据: %d\n, id, shared_data); // 模拟读取耗时 usleep(100000); pthread_rwlock_unlock(rwlock); // 间隔一段时间再读 usleep(500000); } return NULL; } // 写者线程 void* writer(void* arg) { int id *(int*)arg; while (1) { // 加写锁 pthread_rwlock_wrlock(rwlock); shared_data; printf(写者 %d 修改数据为: %d\n, id, shared_data); // 模拟写入耗时 usleep(200000); pthread_rwlock_unlock(rwlock); // 间隔一段时间再写 usleep(2000000); } return NULL; } int main() { // 初始化读写锁默认读者优先 pthread_rwlock_init(rwlock, NULL); pthread_t readers[3], writers[2]; int reader_ids[3] {1, 2, 3}; int writer_ids[2] {1, 2}; // 创建3个读者线程 for (int i 0; i 3; i) { pthread_create(readers[i], NULL, reader, reader_ids[i]); } // 创建2个写者线程 for (int i 0; i 2; i) { pthread_create(writers[i], NULL, writer, writer_ids[i]); } // 运行一段时间后退出示例用sleep sleep(10); // 销毁读写锁 pthread_rwlock_destroy(rwlock); return 0; }设置写者优先示例#include stdio.h #include pthread.h #include unistd.h pthread_rwlock_t rwlock; int shared_counter 0; void* reader_func(void* arg) { int id *(int*)arg; for (int i 0; i 5; i) { pthread_rwlock_rdlock(rwlock); printf(读者 %d 读取: %d\n, id, shared_counter); usleep(50000); // 模拟读取 pthread_rwlock_unlock(rwlock); usleep(100000); } return NULL; } void* writer_func(void* arg) { int id *(int*)arg; for (int i 0; i 3; i) { pthread_rwlock_wrlock(rwlock); shared_counter; printf(写者 %d 写入: %d\n, id, shared_counter); usleep(100000); // 模拟写入 pthread_rwlock_unlock(rwlock); usleep(500000); } return NULL; } int main() { // 设置写者优先 pthread_rwlockattr_t attr; pthread_rwlockattr_init(attr); pthread_rwlockattr_setkind_np(attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); pthread_rwlock_init(rwlock, attr); pthread_t readers[5], writers[2]; int reader_ids[5] {1, 2, 3, 4, 5}; int writer_ids[2] {1, 2}; // 创建线程 for (int i 0; i 5; i) { pthread_create(readers[i], NULL, reader_func, reader_ids[i]); } for (int i 0; i 2; i) { pthread_create(writers[i], NULL, writer_func, writer_ids[i]); } // 等待线程结束 for (int i 0; i 5; i) { pthread_join(readers[i], NULL); } for (int i 0; i 2; i) { pthread_join(writers[i], NULL); } pthread_rwlock_destroy(rwlock); pthread_rwlockattr_destroy(attr); return 0; }