我有一个类似于这个的模板类:
template <typename T>
class Foo {
public:
static void show () {
unique_lock<mutex> l {mtx};
for (const auto& v : vec) {
cout << v << endl;
}
}
static void add (T s) {
unique_lock<mutex> l {mtx};
vec.push_back (s);
}
private:
static mutex mtx;
static vector<T> vec;
};
template <typename T> mutex Foo<T>::mtx;
template <typename T> vector<T> Foo<T>::vec;
这个类的用法如下:
Foo<string>::add ("d");
Foo<string>::add ("dr");
Foo<string>::add ("dre");
Foo<string>::add ("drew");
Foo<string>::show ();
你能告诉我这个类是否是线程安全的吗?如果不是,如何制作一个线程安全的版本?
如果我有一个带有成员函数(非静态)和互斥(不是静态)的类,我就能正确理解它,我们可以防止已通过线程传递的单个对象的竞争条件,对吧?当我们有类似的东西时,我们防止竞争条件不是对象而是对于类而言 - 在这种情况下对于特定类型,或者我错了吗?
答案 0 :(得分:0)
对我来说很好看。向上和向上。
mtx
是'保护'vec,以确保在show()
期间修改向量时,add()
中的迭代无法进行。
如果这是它的角色,请考虑将其称为vec_mtx
。
向上和向上? 首先,你的使用并没有(实际上)表明发生任何线程,所以我(非常)不知道你想要实现什么。
例如,如果所有这些添加都在一个帖子中进行并在另一个帖子中显示,那么您的代码(显然)将无法确保在show之前发生所有。 它只会确保(逻辑上)它发生在所有这些之前,严格地发生在它们中的两个之间或之后。
虽然如果保留对传入的字符串对象的引用或使用带有“浅”复制构造函数的类型T,但不适用于您的用例,那么您可能遇到麻烦。
考虑Foo :: add(缓冲区);并继续修改缓冲区,使show()在一个线程中执行,而strcat(buffer,.)
在另一个线程上执行,缓冲区暂时不是'\ 0'终止。繁荣!预订Seg Fault City的门票(那里的草绿色和女孩不是很漂亮)。
您需要努力(真正的努力)了解共享的数据和方式。 对于所有X,几乎所有不合格的语句“X是线程安全的”都是错误的。 您应始终(始终)确定其安全使用的用途和/或其安全范围。 这对于模板来说是10次。
几乎所有的模板'保证'都可以通过使用某种C数组(或者复杂的结构拿着指针或在其他地方引用,在这里将其传递到模板中,同时在那里打击它)来吹制。内部副本本身就不安全了!
如果你通过某种线程安全的交换结构(例如队列)共享数据,你会得到某种线程安全的保证而且你再也不需要考虑它并且可以回到你的单身,这是一个反复出现的谬论。线索思考。
这里吸取了教训。
NB:理论上std::string
可以在内存不足的环境中实施,该环境积极地“聚集”复制字符串,使您暴露于您甚至无法想象的竞争条件。你理解的理论。