Есть ли способ проверить, действителен ли итератор? - PullRequest
3 голосов
/ 12 января 2009

Например, для двух потоков, манипулирующих картой контейнера, какой правильный способ проверить, действителен ли итератор (по соображениям производительности)?
Или было бы только косвенным способом, которым это может быть сделано. Пример кода для этого:

#define _SECURE_SCL 1
//http://msdn2.microsoft.com/en-us/library/aa985973.aspx
#define _SECURE_SCL_THROWS 1

#include "map"
#include "string"
#include "exception"
#include "iostream"

using namespace std;

void main(void)
{
    map<string, string> map_test;
    map<string, string>::iterator iter_map_test;

    map_test [ "AAAAA" ] = "11111";
    map_test [ "BBBBB" ] = "22222";
    map_test [ "CCCCC" ] = "33333";

    iter_map_test = map_test.find ("BBBBB");

    map_test.erase ("BBBBB");

    try
    {
        string value = (*iter_map_test).second;
    }
    catch ( exception & e )
    {
            cout << e.what() << endl;
    }
    catch ( ... )
    {
            cout << "generic exception." << endl;
    }
}

Ответы [ 5 ]

9 голосов
/ 12 января 2009

std::map s не являются потокобезопасными. Вы столкнетесь с гораздо худшими проблемами, чем недействительные итераторы, если у вас будет более одного потока, изменяющего одну и ту же карту. Я даже не думаю, что у вас есть гарантия, что вы сможете читать что-либо с карты, пока она изменяется другим потоком.

Некоторые страницы по STL и потоки:

3 голосов
/ 12 января 2009

Если ваш STL не предлагает потокобезопасного std::map, Intel TBB предлагает поточно-ориентированный concurrent_hash_map (стр. 60 и 68).

Если оставить в стороне проблемы безопасности потоков, std::map делает гарантией того, что удаление не сделает недействительными итераторы, кроме удаляемого. К сожалению, не существует is_iterator_valid() метода для проверки имеющихся у вас итераторов.

Может быть возможно реализовать что-то вроде указателей опасности , и у TBB также есть некоторые обходные пути к этой проблеме.

2 голосов
/ 12 января 2009

Если вы реализуете решение для чтения / записи, тогда у вас может быть, что средство записи устанавливает флаг, который делает недействительными все итераторы читателей.

http://en.wikipedia.org/wiki/Readers-writer_lock

Я бы не пытался писать на карту без синхронизации, как упоминали Джош и Пол Томблин.

2 голосов
/ 12 января 2009

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

(Предостережение: я знаю классы Java-коллекций намного лучше, чем STL, но именно так я бы это делал в Java.)

1 голос
/ 17 апреля 2009

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

Сбой в этой последовательности потоков:

Thread0 ................................ Резьба1

Получить итератор-> it0

проверить, что это0 действительно

............................................. Получить итератор -> it1

............................................. Проверьте, что it1 действителен.

Стереть (it0)

............................................. Стереть ( it1)

Вы можете добавить семафор для доступа к общему ресурсу.

...