例如,
// I am using thread safe map from
// code.google.com/p/thread-safe-stl-containers
#include <thread_safe_map.h>
class B{
vector<int> b1;
};
//Thread safe map
thread_safe::map<int, B> A;
B b_object;
A[1] = b_object;
// Non thread safe map.
map<int, B*> C;
C[1] = &A[1].second;
以下操作仍然是线程安全的吗?
Thread1:
for(int i=0; i<10000; i++) {
cout << C[1]->b1[i];
}
Thread2:
for(int i=0; i<10000; i++) {
C[1]->b1.push_back(i);
}
上面的代码有什么问题吗?如果是这样我该怎么办?
是否可以访问非线程安全容器内指针指向的值(线程安全映射中的条目)?
答案 0 :(得分:2)
通常,只要所有线程都可以从多个线程访问STL容器:
从同一容器中读取
以线程安全的方式修改元素
您不能从一个线程push_back
(或erase
,insert
等)并从另一个线程读取。假设您正在尝试访问线程1中的元素,而线程2中的push_back
正处于向量存储的重新分配中。这可能会导致应用程序崩溃,可能会返回垃圾(或者可能会有效,如果你很幸运的话)。
第二个要点适用于以下情况:
std::vector<std::atomic_int> elements;
// Thread 1:
elements[10].store(5);
// Thread 2:
int v = elements[10].load();
在这种情况下,您同时读取和写入原子变量,但是矢量本身不会被修改 - 只有它的元素是。
使用thread_safe::map
修改并不会改变您的任何内容。虽然修改地图是可以的,但修改其元素却不行。将std::vector
置于线程安全的集合中并不会自动使其成为线程安全的。
答案 1 :(得分:2)
不,你在做什么并不安全。实现thread_safe_map
的方式是在每个函数调用的持续时间内锁定:
//Element Access
T & operator[]( const Key & x ) { boost::lock_guard<boost::mutex> lock( mutex ); return storage[x]; }
一旦访问功能结束就会释放锁定,这意味着您通过返回的引用进行的任何修改都没有保护。
除了不完全安全之外,这种方法也很慢。
这里提出了一种安全(呃),高效但高度实验性的锁定容器的方法:https://github.com/isocpp/CppCoreGuidelines/issues/924 源代码https://github.com/galik/GSL/blob/lockable-objects/include/gsl/gsl_lockable(无耻的自我推销免责声明)。