【发布时间】:2009-07-08 17:39:11
【问题描述】:
有人知道用于 c++ 的快速而肮脏的线程安全向量类吗?我正在对一些代码进行多线程处理,我相信我遇到的问题与向量的使用方式有关。我计划重写代码,但在我疯狂地重做代码之前,我想用线程安全向量对其进行测试以确保它。我还想如果有这样的东西,它会比编写我自己的版本容易得多。
【问题讨论】:
标签: c++ multithreading thread-safety
有人知道用于 c++ 的快速而肮脏的线程安全向量类吗?我正在对一些代码进行多线程处理,我相信我遇到的问题与向量的使用方式有关。我计划重写代码,但在我疯狂地重做代码之前,我想用线程安全向量对其进行测试以确保它。我还想如果有这样的东西,它会比编写我自己的版本容易得多。
【问题讨论】:
标签: c++ multithreading thread-safety
由于算法,这很困难。
假设您包装了 vector 以便它的所有成员函数都使用互斥锁进行序列化,就像 Java 同步方法一样。然后在该向量上并发调用 std::remove 仍然不安全,因为他们依赖于查看向量并根据他们看到的内容进行更改。
因此,您的 LockingVector 需要在标准算法中专门化每个模板,以锁定整个事物。但是像std::remove_if 这样的其他算法将在锁定下调用用户定义的代码。一旦有人开始创建对象向量,这些对象本身在内部对所有方法进行锁定,就在幕后默默地执行此操作是锁定反转的秘诀。
回答您的实际问题:对不起,不,我不知道。对于您需要的那种快速测试,我建议您从以下开始:
template <typename T>
class LockedVector {
private:
SomeKindOfLock lock;
std::vector<T> vec;
};
然后将其作为替换容器放入,并开始实现成员函数(以及成员 typedef 和运算符),直到它编译为止。您会很快注意到,如果您的任何代码在向量上使用迭代器,而这种方式根本无法从内到外实现线程安全,并且如果需要,您可以在这些情况下临时更改调用代码以锁定向量通过公共方法。
【讨论】:
您可以查看TBB(如concurrent_vector)。虽然我从未使用过它,但老实说,我发现将范围保护对象放在访问周围更容易(特别是如果向量被正确封装)。
【讨论】:
我认为您会发现继续使用 std::vector 会容易得多,但使用某种互斥锁或其他操作系统同步对象来保护并发访问。如果您使用互斥体,您肯定也想使用 RAII。
【讨论】:
正如 Scott Meyers 在有效的 STL 书中所解释的,通过线程安全容器,您可以期望:
仅此而已。您不能指望许多其他事情,例如对同一个容器的多次写入是线程安全的。如果这就是您想要的,那么您可以查看STLPort。如果不是,那么我看到的唯一选择是将向量包含在一个同步访问向量的类中。
【讨论】:
x(不受锁保护)并在每次写入时触摸它,或者他可以添加一个被读取触摸的mutable成员,或类似的东西。
我忘记了谁讨论过这个,但是制作线程安全容器的一种策略如下:
f = myvec[i],而是使用if (myvec.tryGet(i, &f)) {...} 并相应地实现该类。注意:小心迭代。您必须聪明地使用边界检查迭代器维护永不收缩的向量,否则您的代码可能会出现缓冲区溢出类型错误。
提供“线程安全”向量的蹩脚而简单的方法是只采用标准向量并将向量锁定在每个方法上。但如果你这样做,你仍然可能会得到损坏的代码(例如,从 0 迭代到 vec.count 的循环在迭代时可能会改变计数)。
提供“线程安全”容器的第二种方法是创建不可变容器(每个方法都返回一个新容器。这绝对是discussed by Eric Lippert。它是 C#,但大多数情况下很容易转换为 C++ 代码。你仍然会使用时需要锁定容器,但是当迭代器中断时所有涉及缓冲区溢出的可怕问题都会消失。实现不可变容器可能是函数式编程经验丰富的人的第二本能。
【讨论】:
如果您还没有,请考虑使用 tbb 库中的 concurrent_vector。 C++ STL 向量不是线程安全的,因此如果您打算从多个线程修改向量资源,我发现最简单的解决方案是使用 concurrent_vector。
【讨论】: