STLempty()线程安全吗?

发布于 2024-10-03 11:08:26 字数 342 浏览 0 评论 0原文

我有多个线程修改 stl 向量和 stl 列表。
我想避免在容器为空时必须锁定

以下代码是否是线程安全的?如果项目是列表或地图怎么办?

class A  
{  
    vector<int> items  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            AquireLock();  
            DoStuffWithItems();  
            ReleaseLock();  
        }  
     }  
}  

I have multiple threads modifying an stl vector and an stl list.
I want to avoid having to take a lock if the container is empty

Would the following code be threadsafe? What if items was a list or a map?

class A  
{  
    vector<int> items  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            AquireLock();  
            DoStuffWithItems();  
            ReleaseLock();  
        }  
     }  
}  

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

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

发布评论

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

评论(5

深巷少女 2024-10-10 11:08:26

这取决于您的期望。其他答案是正确的,一般,标准 C++ 容器不是线程安全的,此外,特别您的代码不会阻止另一个线程修改容器在调用empty和获取锁之间(但这件事与vector::empty的线程安全无关)。

因此,为了避免任何误解:您的代码不保证块内的items将非空。

但是您的代码仍然有用,因为您想要的一切要做的就是避免多余的锁创建。您的代码不提供保证,但它可能防止创建不必要的锁。它并非在所有情况下都有效(其他线程仍然可以清空支票和锁之间的容器),但在某些情况下有效。如果您所追求的只是通过省略冗余锁来进行优化,那么您的代码就可以实现该目标。

只需确保对容器的任何实际访问都受到锁的保护。

顺便说一句,严格来说,上面是未定义的行为:理论上,STL 实现允许修改 调用中的可变 成员空。这意味着对 empty 看似无害(因为只读)的调用实际上可能会导致冲突。不幸的是,您不能依赖这样的假设:只读调用对于 STL 容器是安全的。

但实际上,我非常确定 vector::empty 不会修改任何成员。但对于 list::empty 我不太确定。如果您确实想要保证,那么要么锁定每个访问,要么不使用STL容器。

It depends what you expect. The other answers are right that in general, standard C++ containers are not thread-safe, and furthermore, that in particular your code doesn’t ward against another thread modifying the container between your call to empty and the acquisition of the lock (but this matter is unrelated to the thread safety of vector::empty).

So, to ward off any misunderstandings: Your code does not guarantee items will be non-empty inside the block.

But your code can still be useful, since all you want to do is avoid redundant lock creations. Your code doesn’t give guarantees but it may prevent an unnecessary lock creation. It won’t work in all cases (other threads can still empty the container between your check and the lock) but in some cases. And if all you’re after is an optimization by omitting a redundant lock, then your code accomplishes that goal.

Just make sure that any actual access to the container is protected by locks.

By the way, the above is strictly speaking undefined behaviour: an STL implementation is theoretically allowed to modify mutable members inside the call to empty. This would mean that the apparently harmless (because read-only) call to empty can actually cause a conflict. Unfortunately, you cannot rely on the assumption that read-only calls are safe with STL containers.

In practice, though, I am pretty sure that vector::empty will not modify any members. But already for list::empty I am less sure. If you really want guarantees, then either lock every access or don’t use the STL containers.

深海夜未眠 2024-10-10 11:08:26

STL 的容器和算法中的任何内容都没有线程安全保证。

所以,不。

There is no thread-safe guaranty on anything in the containers and algorithms of the the STL.

So, No.

假面具 2024-10-10 11:08:26

无论空是否是线程安全的,您的代码都不会像编写的那样实现您的目标。

class A  
{  
    vector<int> items  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            //Another thread deletes items here.
            AquireLock();  
            DoStuffWithItems();  
            ReleaseLock();  
        }  
     }  
}  

更好的解决方案是每次使用 items 时(迭代、获取项目、添加项目、检查计数/空性等时)进行锁定,从而提供您自己的线程安全性。因此,首先获取锁,然后检查向量是否为空。

Regardless of whether or not empty is thread safe, your code will not, as written, accomplish your goal.

class A  
{  
    vector<int> items  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            //Another thread deletes items here.
            AquireLock();  
            DoStuffWithItems();  
            ReleaseLock();  
        }  
     }  
}  

A better solution is to lock every time you work with items (when iterating, getting items, adding items, checking count/emptiness, etc.), thus providing your own thread safety. So, acquire the lock first, then check if the vector is empty.

爱的十字路口 2024-10-10 11:08:26

正如已经回答的那样,上面的代码不是线程安全的,并且在实际对容器执行任何操作之前必须强制锁定。
但以下应该比总是锁定具有更好的性能,并且我想不出它不安全的原因。
这里的想法是,锁定可能会很昂贵,并且只要不是真正需要的时候,我们就会避免使用它。

class A
{
    vector<int> items;  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            AquireLock();
            if(!items.empty())
            {
                DoStuffWithItems();  
            }
            ReleaseLock();  
        }
     }
 }  

As it is already answered, the above code is not thread safe and locking is mandatory before actually doing anything with the container.
But the following should have better performance than always locking and I can't think of a reason that it can be unsafe.
The idea here is that locking can be expensive and we are avoiding it, whenever not really needed.

class A
{
    vector<int> items;  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            AquireLock();
            if(!items.empty())
            {
                DoStuffWithItems();  
            }
            ReleaseLock();  
        }
     }
 }  
无言温柔 2024-10-10 11:08:26

STL 不是线程安全的,也是空的。如果你想让容器安全,你必须通过互斥或其他同步关闭它的所有方法

STL is not thread safe and empty too. If you want make container safe you must close all its methods by mutex or other sync

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