std::list 线程push_back、front、pop_front

发布于 2024-08-13 14:37:13 字数 1412 浏览 1 评论 0原文

std::list 线程安全吗?我假设不是这样,所以我添加了自己的同步机制(我认为我有正确的术语)。但我仍然遇到问题

每个函数都由单独的线程调用。 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();
    }
}

在对 thread1 进行大约 170k 调用和对 thread2 进行 900k 调用之后,我在 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

条建议、评论,是否有更好的做事方法?

Is std::list thread safe? I'm assuming its not so I added my own synchronization mechanisms (I think i have the right term). But I am still running into problems

Each function is called by a separate thread. Thread1 can not wait, it has to be as fast as possible

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();
    }
}

After about 170k calls to thread1 and 900k calls to thread2 I get an exception error on CFoo& pFoo = g_buffer.front() ;

That causes the program to crash. 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

Suggestions, comments, is there a better way of doing things?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

萧瑟寒风 2024-08-20 14:37:13

std::list 线程安全吗?

当前的 C++ 标准甚至不承认线程的存在,因此 std::list 当然不承认。然而,不同的实现可能提供(不同级别的)线程安全性。

至于你的代码:如果你需要锁,就使用锁。当线程在不同的内核上执行并从不同的缓存获取该变量时,该 bool 变量可能没有帮助。请改用真正的互斥体。

Is std::list thread safe?

The current C++ standard doesn't even acknowledge the existence of threads, so std::list certainly isn't. Different implementations, however, might provide (different levels of) thread safety.

As for your code: If you need a lock, use a lock. That bool variable might not help when the threads are executed on different cores which fetch it from different caches. Use a real mutex instead.

隔纱相望 2024-08-20 14:37:13

不,它不能保证线程安全。

你的同步机制有缺陷。您允许 thread1thread2 使用列表时更改该列表。这可能会导致问题。除此之外,您应该使锁变量易失性

No, it's not guaranteed to be thread safe.

Your synchronization mechanism is flawed. You are allowing thread1 to change the list while thread2 is working with it. This can cause problems. Besides that, you should make your lock variable volatile.

溺孤伤于心 2024-08-20 14:37:13

您假设 stl 列表不能保证线程安全是正确的。

另外,您的同步机制可能不太好。

在 thread2 内部,您没有锁定您的布尔值,因此您在那里遇到了问题。

您至少应该在 lock bool 前面放置一个易失性限定符;或者最好还是研究适合您平台的真正互斥函数。

You are correct in presuming that an stl list is not guaranteed to be thread-safe.

Also your synchronization mechanism isn't likely very good.

Inside thread2 you don't lock your bool, so you have a problem there.

You should likely as a minimum put a volatile qualifier in front of your lock bool; or better still look into real mutex functions appropriate to your platform.

番薯 2024-08-20 14:37:13

仅仅因为 Thread1 需要尽可能快,并不意味着可以让它在另一个线程更改列表时访问该列表。由于两个线程都在修改列表,因此都必须等待。如果最终数据损坏,速度再快也无济于事。

编辑:

实际上你可能会侥幸逃脱...... Thread1 只将元素添加到列表中,而 Thread2 只删除它们。这意味着如果列表仅包含一个元素,则 Thread1 仅需要等待。

Edit2:

因此,完成这项工作的方法是线程 2 锁定列表(如果列表仅包含一个元素)。每次删除之前都必须进行检查。这样,除了这种情况之外,thread1 就不必等待。

而且您绝对应该使用适当的互斥机制(无论您的平台上有什么可用的机制)而不是布尔标志。

Just because Thread1 needs to be as fast as possible, it doesn't mean that it is ok to let it access a list while it is being changed by another thread. Since both threads are modifying the list, both have to wait. Being fast doesn't help if you end up with corrupt data.

Edit:

Actually you may get away with it... Thread1 only adds elements to the list, while Thread2 only removes them. This means that Thread1 only needs to wait if the list only contains one element.

Edit2:

So, the way to make this work is for thread2 to lock the list if it only contains one element. It would have to check that before every deletion. This way thread1 would not have to wait except for that one case.

And you definitely should use a proper mutual exclusion mechanism (whatever is available on your platform) rather than a boolean flag.

如梦 2024-08-20 14:37:13

如果您确实需要 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 必须始终锁定。您也许可以想出一些方法来为线程 1 批处理帧。根据您在问题中的数字,我假设 thread1 运行的次数比 thread2 运行的次数多得多,因此这将节省一些锁定争用,否则仅使用一个缓冲区列表就会发生这种争用。

If you really need thread1 to be as fast as possible, but still need thread safety, you can prevent some lock contention at the cost of a minimal amount of overhead, as such:

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();
    }
}

I think this is the most straightforward combination with thread safety. Thread1 must always lock, unfortunately. You might be able to come up with something where you batch frames for thread1. I'm assuming, based on your numbers in the question, that thread1 runs many more times than does thread2, so this will save some lock contention that would otherwise occur by using just one buffer list.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文