使STL容器线程安全的类(转载)

本文介绍了C++的ThreadSafeObject类,它是一个线程安全的包装类,利用Windows API临界区逻辑,能将任意对象转换为线程安全对象。其析构函数会自动销毁对象,还给出了使用示例,如创建线程安全的向量和字符串对象。
C++ code colored by C++2HTML
// ThreadSafeObject.h 
//  ThreadSafeObject by David Maisonave (609-345-1007) (www.axter.com)
/*
Description:ThreadSafeObject is a thread safe wrapper class, 
which uses windows API Critical-Section logic. 
It can turn any object into a thread safe object.
ThreadSafeObject destructor will automatically destroy the object,
so the object can be create via new on ThreadSafeObject constructor.
This insures no other process has ownership of the object.
Example Usage
ThreadSafeObject<vector<int> > MyThreadSafeVectorInt(new vector<int>);
MyThreadSafeVectorInt.GetLockedObject()->push_back(123);
cout << MyThreadSafeVectorInt.GetLockedObject()->at(0) << endl;

//An instance of RefLock can be create to lock the object for the duration of a function.
Example Usage
ThreadSafeObject<string> MyThreadSafeString(new string);

string SomeFunction()
{
ThreadSafeObject<string>::RefLock MyLockedString = MyThreadSafeString.GetLockedObject();
MyLockedString->operator=("Hello World");
return MyLockedString->substr(6);
}

//The destructor for RefLock automatically unlocks the object, so an explicit unlock call
//is not required.
*/

#ifndef THREADSAFEOBJECT_H_HEADER_GUARD_
#define THREADSAFEOBJECT_H_HEADER_GUARD_

template<class T>
class ThreadSafeObject
{
public:
     ThreadSafeObject(T* type):m_type(type){InitializeCriticalSection(&m_cs);}
     ~ThreadSafeObject()
     {
          EnterCriticalSection (&m_cs);
          delete m_type;m_type=NULL;
          LeaveCriticalSection(&m_cs);
          DeleteCriticalSection(&m_cs);
     }
     class RefLock
     {
     public:
          RefLock(T* type, CRITICAL_SECTION &cs):m_type(type), m_cs(cs){ EnterCriticalSection (&m_cs);}
          RefLock(const RefLock& Src):m_type(Src.m_type), m_cs(Src.m_cs){ EnterCriticalSection (&m_cs);}
          ~RefLock(){LeaveCriticalSection(&m_cs);}
          inline T* operator->() const{return m_type;}
          inline T& operator*() const{return m_type;}
          T* m_type;
     private:
          CRITICAL_SECTION &m_cs;
     };
     RefLock GetLockedObject()
     {
          return RefLock(m_type, m_cs);
     }
private:
     T* m_type;
     CRITICAL_SECTION m_cs;
     ThreadSafeObject(const ThreadSafeObject&);
     ThreadSafeObject& operator=(const ThreadSafeObject&);
};

#endif //!THREADSAFEOBJECT_H_HEADER_GUARD_
<think>嗯...用户问的是STL容器线程安全性,这个问题其实在C++多线程编程中挺关键的。从用户引用的资料来看,ta应该已经查了不少资料,但可能被不同来源的说法搞糊涂了——引用1说只有读取安全,引用2提到C++11有线程安全版本,引用3又说全部需要同步... 用户需要的是权威结论。 用户可能正在写多线程程序时遇到了容器崩溃的问题,或者是在设计架构时考虑线程安全方案。ta引用的资料时间跨度较大,需要帮ta理清不同C++标准的差异... 首先得明确核心原则:标准STL容器本身不是线程安全的(除了特例),这点五个引用其实都认同。不过引用2提到的_safe和_mt后缀容易误导人——查了C++标准文档确认过,这些其实是某些编译器扩展,根本不是标准内容!得提醒用户注意这点。 用户摘录的引用5特别重要,它点出了迭代器失效这个深坑。很多程序员知道用mutex保护insert/erase,却忘了正在使用的迭代器可能失效。这个典型案例值得展开说明。 另外注意到用户贴出了自定义线程安全容器的代码片段(引用4),说明ta可能更需要实践方案而非理论。应该重点给出三种实现方案的优缺点对比:mutex锁方案、并发容器方案、TLS方案。特别是C++17的scoped_lock要强调下,比手动lock/unlock安全多了。 对了,用户没提标准版本,但引用2涉及C++11前后差异。需要补充说明:C++11前连内存模型都没有,根本谈不上线程安全;C++11后至少有内存序保证,但容器操作仍非原子。 最后那个"从容器角度"的表格总结很有必要,用户看起来是工程师思维,表格比文字更直观。不过要注明"标准未定义"这点,避免用户误以为是规范要求。 </think>关于STL容器线程安全性,综合引用资料和C++标准规范,核心结论如下: ### 📌 线程安全性结论 1. **原生STL容器线程安全** 标准库的STL容器(如 `vector`, `map`, `list` 等)**本身不提供线程安全保证**(除极少数特例)。多个线程同时读写同一容器需显式同步[^1][^3][^5]。 2. **例外情况(只读或独立写)** 仅以下场景安全: - 多个线程**只读**同一容器 ✅ - 多个线程**写不同容器** ✅ > *示例:线程A写`map1`,线程B写`map2`,线程C读`map1`均安全* 3. **常见风险场景** - 并发读写同一容器(如生产者写入`vector`,消费者读取) ❌ - 迭代器失效(如其他线程修改容器导致迭代器悬空) ❌ [^5] - 容器内部结构变更(如`map`红黑树调整时并发访问) ❌ [^5] --- ### 🛡️ 线程安全实现方案 针对不同需求场景的解决方案: | **方法** | **适用场景** | **实现示例** | |------------------------|--------------------------------|-----------------------------------------------------------------------------| | **原生容器 + 互斥锁** | 通用场景,C++11前/后均可 | 使用`std::mutex`封装操作(构造函数加锁,析构解锁)[^3][^4] | | **并发容器(C++11+)** | 高性能需求,避免锁竞争 | 第三方库(如TBB)或编译器扩展容器(如`vector_safe`, `map_mt`)[^2] | | **线程局部存储(TLS)** | 避免共享,线程独立操作容器 | 使用`thread_local`声明容器副本,线程退出后合并结果[^2] | ```cpp // 互斥锁封装示例(C++11) #include <mutex> #include <vector> template<typename T> class ThreadSafeVector { public: void push(const T& value) { std::lock_guard<std::mutex> lock(mtx); data.push_back(value); } // 其他操作似封装... private: std::vector<T> data; std::mutex mtx; }; ``` --- ### ⚠️ 关键注意事项 1. **迭代器安全** 即使容器本身被保护,**持有迭代器期间**容器被修改仍会导致未定义行为[^5]。 > *建议*:临界区内完成迭代器使用或改用索引访问。 2. **C++11内存模型** C++11标准定义了内存序(Memory Order),但**未要求容器操作原子性**,仍需手动同步[^2][^3]。 3. **伪线程安全容器** 部分编译器提供`_safe`/`_mt`后缀容器(如`std::vector_safe`),但**非C++标准**,可移植性差[^2]。 --- ### 📚 总结建议 | **容器操作型** | **是否需要同步** | **推荐方案** | |----------------|----------------|--------------------------------| | **多线程并发读** | ❌ 否 | 直接使用原生容器 | | **多线程混合读写**| ✅ 是 | 互斥锁封装 或 并发容器 | | **高频写操作** | ✅ 是 | 无锁队列(如`boost::lockfree`) | > 简言之:**标准STL容器线程安全,需开发者自行保证同步**。优先使用标准库锁(`std::mutex`)或并发容器库(如Intel TBB)[^1][^3][^4]。 --- ### ❓相关问题 1. 如何在C++11中实现无锁(lock-free)的线程安全容器? 2. STL容器的哪些操作会导致迭代器失效?如何避免多线程下的迭代器失效问题? 3. 除了互斥锁,还有哪些机制可保证STL容器线程安全(如信号量、原子操作)? ##### 参考资料 [^1]: STL线程安全讨论 [^2]: STL容器线程安全性? [^3]: STL线程安全 [^4]: STL容器线程安全 [^5]: UNIX(多线程)STL容器线程安全
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值