我有一个标准向量和多个线程。我正在使用以下代码在需要时锁定:
boost::mutex::scoped_lock lock(mutex);
这个工作正常,应用程序运行没有任何问题,但现在我为向量创建了一个小类,以使我的生活更轻松:
template <class T> class FVector
{
private:
std::vector<T> standard_vector;
mutable boost::mutex mutex;
public:
typedef typename std::vector<T>::iterator iterator;
typedef typename std::vector<T>::size_type size_type;
FVector(void)
{
}
iterator begin(void)
{
boost::mutex::scoped_lock lock(mutex);
return standard_vector.begin();
}
iterator end(void)
{
boost::mutex::scoped_lock lock(mutex);
return standard_vector.end();
}
void push_back(T & item)
{
boost::mutex::scoped_lock lock(mutex);
standard_vector.push_back(item);
}
void erase(iterator it)
{
boost::mutex::scoped_lock lock(mutex);
standard_vector.erase(it);
}
};
但遗憾的是它不起作用。我只是得到 xx.exe已经触发了断点。异常,这意味着锁和多个线程在同一时间尝试写入和读取有问题。
我正在使用以下代码进行测试:
#include <Windows.h>
#include <process.h>
#include "thread_safe_vector.h"
struct TValue
{
int value;
};
FVector<TValue> vec_Safe;
boost::mutex testMutex;
void thread2(void* pArg)
{
while (true)
{
//boost::mutex::scoped_lock lock(testMutex);
for (FVector<TValue>::iterator it = vec_Safe.begin(); it != vec_Safe.end(); it++)
{
if (it->value == 5)
{
vec_Safe.erase(it);
break;
}
}
}
}
void thread1(void* pArg)
{
while (true)
{
TValue value;
value.value = 5;
//boost::mutex::scoped_lock lock(testMutex);
vec_Safe.push_back(value);
}
}
void main(void)
{
HANDLE hThreads[50];
for (size_t i = 0; i < 50; i++)
{
hThreads[i] = (HANDLE)_beginthread(i % 2 == 0 ? thread1 : thread2, NULL, NULL);
}
system("pause");
for (size_t i = 0; i < 50; i++)
{
TerminateThread(hThreads[i], 0);
}
}
我绝对没有想法,我试着找出问题好几个小时......有什么我做错的吗?
答案 0 :(得分:3)
通过将锁定向下移动到较低的抽象级别,您引入了数据竞争。
for (FVector<TValue>::iterator it = vec_Safe.begin(); it != vec_Safe.end(); it++)
此处begin()
和end()
都在锁定下执行,但比较并非如此。更糟糕的是:
{
if (it->value == 5)
取消引用陈旧的迭代器,其他一方修改了它。
更重要的是,任何重新分配操作都可以一举使所有迭代器无效。
您将始终必须锁定整个循环。如果循环体需要很长时间,你可以复制锁下的元素,然后再处理它们。
然而,在这种情况下,使用(lockfree)队列并将元素从共享队列拼接到本地队列以提高效率更为典型。