转 [https://blog.csdn.net/lujin0312/article/details/77776435]
最近做一个印刷品缺陷检测的图像处理的项目,是实时处理的。采用了多线程的方式,线程A负责从相机中取数据,线程B负责处理取到的数据。由于相机数据是以固定时间间隔过来,而且不能等待,所以我就想到利用一个双向链表来保存数据,线程A不停地往链表的尾部添加数据,线程B从链表头部取走数据,然后将表头节点pop出去。感觉上这两个线程虽然同时对链表进行操作,但是一个是往尾部追加数据,一个从头部取数据,似乎不会发生冲突,所以也没有加锁。但是运行过程中偶尔会出错,弹出itrator not refrenceable之类的错误。
我怀疑是由于list并不是线程安全的,所以两个线程同时对list进行操作会应发莫名其妙的问题。于是我写了一个简单的小程序测试一下。
#include "stdafx.h"
#include<iostream>
#include<process.h>
#include<windows.h>
#include<list>
using namespace std;
class CBaselock
{
public:
CBaselock()
{
InitializeCriticalSection(&m_Sec);//初始化临界区
}
~CBaselock()
{
DeleteCriticalSection(&m_Sec);
}
void Lock()
{
EnterCriticalSection(&m_Sec);
}
void UnLock()
{
LeaveCriticalSection(&m_Sec);
}
private:
CRITICAL_SECTION m_Sec;
};
class CTestList
{
public:
CTestList() {};
~CTestList() {};
long Start();
static unsigned __stdcall PushThred(void * pThis)
{
CTestList * pthX = (CTestList*)pThis; // the tricky cast
pthX->pushFunc(); // now call the true entry-point-function
return 1; // the thread exit code
}
static unsigned __stdcall PopThred(void * pThis)
{
CTestList * pthX = (CTestList*)pThis; // the tricky cast
pthX->popFunc(); // now call the true entry-point-function
return 1; // the thread exit code
}
long pushFunc();
long popFunc();
list<int> m_list;
CBaselock m_lock;
};
long CTestList::Start()
{
_beginthreadex(NULL, 0, &PushThred, this, 0, 0);
_beginthreadex(NULL, 0, &PopThred, this, 0, 0);
return 1;
}
long CTestList::pushFunc()
{
int index = 0;
while (1)
{
//m_lock.Lock();
printf("push:%d,list size:%d\n", index, m_list.size());
m_list.push_back(index);
//m_lock.UnLock();
++index;
//Sleep(0);
}
return 1;
}
long CTestList::popFunc()
{
while (1)
{
if (m_list.size() > 0)
{
//m_lock.Lock();
printf("pop:%d,list size:%d\n", m_list.front(), m_list.size());
m_list.pop_front();
//m_lock.UnLock();
//Sleep(0);
}
}
return 1;
}
int main()
{
CTestList testObj;
testObj.Start();
int a = 0;
std::cin >> a;
return 0;
}
在没有加锁时,测试时偶尔会弹出错误,于是老老实实加锁,测试没有报错了。
总结一点,stl list不是线程安全的,在多线程下使用时一定要记得加锁。