对于std :: list l, 在thread1中,我做到了 l.push_back 在thread2中,我做到了 while(l.size()> 1)l.pop_front() 当这两个线程同时运行时,我得到了数据竞争。
让我感到困惑的是,我在pop_front之前检查过l.size是否大于1, 所以,当push_back时,没有任何情况下被推回的对象会有一个Null的前身, 然后我无法理解为什么会有数据竞争。
以下是我的测试中的代码:
#include <windows.h>
#include <list>
using namespace std;
HANDLE gsem = CreateSemaphore(NULL, 2, 2, NULL);
unsigned long __stdcall threadPoc(list<int>* l);
unsigned long __stdcall threadPoc2(list<int>* l);
int main()
{
std::list<int> l;
unsigned long a1, a2;
HANDLE t[2];
t[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadPoc, &l, 0, &a1);
t[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadPoc2, &l, 0, &a2);
ReleaseSemaphore(gsem, 2, NULL);
WaitForMultipleObjects(2, t, TRUE, INFINITE);
return 0;
}
bool exf = false;
unsigned long __stdcall threadPoc(list<int>* l)
{
WaitForSingleObject(gsem, INFINITE);
for (int i=0; i<100000; i++)
l->push_back(i);
exf = true;
return 0;
}
unsigned long __stdcall threadPoc2(list<int>* l)
{
WaitForSingleObject(gsem, INFINITE);
while (l->size()>1 || !exf)
l->pop_front();
return 0;
}
答案 0 :(得分:0)
在列表背面添加元素时,通常需要执行以下操作:
如果您的列表包含1个元素,而另一个线程在步骤1和2之间删除了该元素,则您的列表将会损坏。
使用互斥锁(CriticalSection)保护列表,或使用无锁列表(例如Microsoft的PPL库中的concurrent_queue,请参阅http://msdn.microsoft.com/en-us/library/dd504906.aspx#queue)。
答案 1 :(得分:0)
并发是一个很大的话题,首先我建议你阅读Anthony Williams的“C ++ Concurrency in Action”,你会在阅读完这本书后了解几乎所有内容。
首先,记住一件事,一个线程写入时总会发生冲突,另一个线程读/写同一个对象。
其次,对于你的具体问题,显然有几个冲突的地方。
l.push_back很可能(好吧,取决于列表实现)改变大小,l.size()是一个读取,所以它是在相同变量大小上的写 - 读冲突。并且l.pop_front也很可能会改变大小,因此它是写 - 写冲突。考虑什么时候push_back和amp; pop_front更改大小,大小将会损坏。
似乎l.push_back&amp; l.pop_front没有写入 - 写入冲突,因为C ++的列表是一个双向链表,而push_back / pop_front没有处理同一个变量,但你可能错了。一个显而易见的事情是,push_back()可能涉及内存分配,pop_front()可能涉及内存释放。内存填充由template-id Alloc处理。您很有可能内存分配/释放存在冲突。这完全取决于实现,其中不同的库可能有不同的实现。