std :: list thread是否安全?我假设它不是这样我添加了自己的同步机制(我认为我有正确的术语)。但我仍然遇到问题
每个函数都由一个单独的线程调用。 Thread1不能等待,它必须尽可能快
std::list<CFoo> g_buffer;
bool g_buffer_lock;
void thread1( CFoo frame ) {
g_buffer_lock = true ;
g_buffer.push_back( frame ) ;
g_buffer_lock = false;
}
void thread2( )
{
while( g_buffer_lock ) {
// Wait
}
// CMSTP_Send_Frame * pMSTPFrame = NULL ;
while ( ! g_buffer_lock && g_buffer.size() > 0 )
{
// Get the top item
CFoo& pFoo = g_buffer.front() ;
// Do something.
// remove the front item
g_buffer.pop_front();
}
}
在大约170k调用thread1和900k调用thread2后,我在CFoo& pFoo = g_buffer.front() ;
导致程序崩溃。 stdthrow.cpp:22
#ifdef _DEBUG
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Debug_message(const wchar_t *message, const wchar_t *file, unsigned int line)
{ // report error and die
if(::_CrtDbgReportW(_CRT_ASSERT, file, line, NULL, message)==1)
{
::_CrtDbgBreak();
}
}
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL _Debug_message(const unsigned short *message, const unsigned short *file, unsigned int line)
{ // report error and die
_Debug_message((wchar_t *) message, (wchar_t *) file, line);
}
#endif
建议,意见,是否有更好的做事方式?
答案 0 :(得分:15)
std :: list thread是否安全?
当前的C ++标准甚至不承认线程的存在,因此std::list
当然不是。然而,不同的实现可能提供(不同级别的)线程安全性。
至于你的代码:如果你需要锁,请使用锁。当线程在不同的核心上执行时,bool
变量可能无效,这些核心从不同的缓存中获取它。请改用真正的互斥锁。
答案 1 :(得分:6)
不,它不能保证是线程安全的。
您的同步机制存在缺陷。 thread1
正在使用thread2
时,您允许volatile
更改列表。这可能会导致问题。除此之外,你应该使你的锁变量{{1}}。
答案 2 :(得分:1)
你认为stl列表不能保证是线程安全的,这是正确的。
您的同步机制也不太可能。
在thread2中,你没有锁定你的bool,所以你遇到了问题。
您应该至少在锁定布尔之前放置一个易变限定符;或者更好地了解适合您平台的真实互斥功能。
答案 3 :(得分:1)
仅仅因为Thread1需要尽可能快,这并不意味着让它在被另一个线程更改时访问列表是可以的。由于两个线程都在修改列表,因此两者都必须等待。如果你最终得到了腐败的数据,那么快速无济于事。
编辑:
实际上你可能会侥幸逃脱...... Thread1只会向列表中添加元素,而Thread2只会删除它们。这意味着如果列表只包含一个元素,则Thread1只需要等待。
EDIT2:
因此,使这项工作的方法是让thread2锁定列表,如果它只包含一个元素。它必须在每次删除之前检查。这样,除了那个案例之外,thread1不必等待。
你绝对应该使用适当的互斥机制(平台上可用的任何东西)而不是布尔标志。
答案 4 :(得分:0)
如果你真的需要thread1尽可能快,但仍然需要线程安全,你可以以最小的开销为代价来防止一些锁争用,如下:
std::list<CFoo> g_buffer_thread1;
std::list<CFoo> g_buffer_thread2;
Mutex g_mutex;
void thread1( CFoo frame ) {
Locker lock( g_mutex );
g_buffer_thread1.push_back( frame ) ;
}
void thread2( )
{
while( g_buffer_thread2.size() == 0 ) {
// Wait?
Locker lock( g_mutex );
g_buffer_thread1.swap( g_buffer_thread2 );
}
while ( g_buffer_thread2.size() > 0 )
{
CFoo& pFoo = g_buffer_thread2.front() ;
// Do something.
g_buffer_thread2.pop_front();
}
}
我认为这是线程安全最直接的组合。不幸的是,Thread1必须始终锁定。您可以想出一些批处理thread1帧的东西。我假设,根据你在问题中的数字,thread1比thread2运行的次数多很多次,所以这将节省一些锁争用,否则只会使用一个缓冲列表。