Является ли STL empty () потокобезопасным? - PullRequest
8 голосов
/ 17 ноября 2010

У меня есть несколько потоков, модифицирующих вектор stl и список stl.
Я хочу избежать блокировки, если контейнер пуст

Будет ли следующий код безопасен для потоков? Что, если предметы были списком или картой?

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

Ответы [ 5 ]

6 голосов
/ 17 ноября 2010

Зависит от того, что вы ожидаете.Другие ответы верны: в общем , стандартные контейнеры C ++ не являются поточно-ориентированными, и, кроме того, что в частности ваш код не защищает другой поток, изменяющий контейнер между вашимивызов empty и получение блокировки (но этот вопрос не связан с безопасностью потока vector::empty).

Итак, чтобы предотвратить любые недоразумения: Ваш код не гарантирует items будет непустым внутри блока.

Но ваш код все еще может быть полезен, поскольку все, что вы хотите сделать, - это избегать создания избыточных блокировок.Ваш код не дает гарантий, но он может предотвратить ненужное создание блокировки.Это не будет работать во всех случаях (другие потоки могут по-прежнему очищать контейнер между проверкой и блокировкой), но в некоторых случаях.И если все, что вам нужно, это оптимизация, исключив избыточную блокировку, то ваш код достигает этой цели.

Просто убедитесь, что любой фактический доступ к контейнеру равен защищено блокировками.

Кстати, это строго говоря неопределенное поведение : теоретически реализация STL позволяет изменять mutable членов внутрипозвоните на empty.Это будет означать, что очевидно безвредный (потому что только для чтения) вызов empty может фактически вызвать конфликт.К сожалению, вы не можете полагаться на предположение, что вызовы только для чтения безопасны с контейнерами STL.

На практике, однако, я вполне уверен, что vector::empty не будет не изменить любой членов.Но уже на list::empty я менее уверен.Если вы действительно хотите, чтобы гарантировал , то либо блокируйте каждый доступ, либо не используйте контейнеры STL.

3 голосов
/ 17 ноября 2010

В контейнерах и алгоритмах STL нет поточно-ориентированной гарантии на что-либо.

Итак, №

2 голосов
/ 17 ноября 2010

Независимо от того, является ли пустой потокобезопасным, ваш код, как написано, не достигнет вашей цели.

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

Лучшее решение - блокировать каждый раз, когда вы работаете с items (при итерации, получении элементов, добавлении элементов, проверке количества / пустоты и т. Д.), Таким образом, обеспечивая собственную безопасность потоков. Итак, сначала получите блокировку, , а затем , проверьте, является ли вектор пустым.

1 голос
/ 22 октября 2015

Как уже было сказано, приведенный выше код не является потокобезопасным, и блокировка обязательна, прежде чем что-либо делать с контейнером.Но следующее должно иметь лучшую производительность, чем всегда блокировка, и я не могу придумать причину, по которой это может быть небезопасно.Идея заключается в том, что блокировка может быть дорогой, и мы избегаем ее, когда она действительно не нужна.

class A
{
    vector<int> items;  
    void DoStuff()  
    {  
        if(!items.empty())  
        {  
            AquireLock();
            if(!items.empty())
            {
                DoStuffWithItems();  
            }
            ReleaseLock();  
        }
     }
 }  
1 голос
/ 17 ноября 2010

STL не является потокобезопасным и пустым. Если вы хотите сделать контейнер безопасным, вы должны закрыть все его методы мьютексом или другой синхронизацией

...