我目前正试图解决使用 C++ STL 容器的线程安全问题。我最近尝试通过使用 std::mutex 作为成员变量来实现线程安全的 std::vector,然后才意识到虽然我可以通过锁定锁使成员函数成为线程安全的,但我无法使 lib 函数像 std::sort 线程安全,因为它们只获得 begin()/end() 迭代器,这是一般 STL 中容器和算法之间基本分离的结果。
所以我想,如果我不能使用锁,软件事务内存(STM)怎么样?
所以现在我坚持这个:
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>
#define LIMIT 10
std::atomic<bool> start{false};
std::vector<char> vec;
void thread(char c)
{
while (!start)
std::this_thread::yield();
for (int i = 0; i < LIMIT; ++i) {
__transaction_atomic {
vec.push_back(c);
}
}
}
int main()
{
std::thread t1(thread, '*');
std::thread t2(thread, '@');
start.store(true);
t1.join();
t2.join();
for (auto i = vec.begin(); i != vec.end(); ++i)
std::cout << *i;
std::cout << std::endl;
return EXIT_SUCCESS;
}
我编译的是:
g++ -std=c++11 -fgnu-tm -Wall
使用 g++ 4.8.2,这给了我以下错误:
error: unsafe function call to push_back within atomic transaction
我有点明白了,因为 push_back 或 sort 或任何未声明 transaction_safe 的东西,但这给我留下了以下问题:
a) 我该如何解决这个错误?
b) 如果我无法修复该错误,那么这些事务块通常用于什么?
c) 如何实现无锁线程安全向量?!
提前致谢!
编辑: 感谢到目前为止的答案,但他们并没有真正抓到我的痒。让我举个例子:假设我有一个全局向量,并且对这个向量的访问应该在多个线程之间共享。所有线程都尝试进行排序插入,因此它们生成一个随机数并尝试以排序方式将此数字插入向量中,因此向量始终保持排序状态(包括 c 的重复项)。为了进行排序插入,他们使用 std::lower_bound 来查找要插入的“索引”,然后使用 vector.insert() 进行插入。
如果我为包含 std::mutex 作为成员的 std::vector 编写包装器,那么我可以编写包装器函数,例如使用 std::lock_guard 锁定互斥锁然后执行实际 std::vector 的插入。插入()调用。但是 std::lower_bound 并不关心成员互斥锁。这是一个功能,而不是一个错误 afaik。
这使我的线程陷入困境,因为其他线程可以在某人做他的 lower_bound 事情时更改向量。
我能想到的唯一解决方法是:忘记包装器并为向量设置一个全局互斥锁。每当有人想对这个向量做任何事情时,他都需要那个锁。
那就是问题所在。使用此全局互斥锁有哪些替代方法。这就是软件事务内存浮现在脑海中的地方。
那么现在:如何在 STL 容器上使用 STM?(和a),b),c)从上面)。