| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > STL и многопоточность |
| Автор: nerdy_weirdie 16.2.2011, 23:30 | ||
| Здравствуйте. Столкнулся со странной проблемой. У меня есть класс CMyList унаследованный от std::list В классе есть 1 метод добавляющий элемент в список и 4 удаляющих. Все они при этом защищены критической секцией. Несмотря на это в следующей функции иногда получаю невалидный итератор:
Иногда на строке SAFEDEL(*it); получаю итератор it = 0xfeeefeee и соответственно дебажная CRT мне говорит "list iterator not dereferencable". Откуда такой итератор мог здесь взяться? |
| Автор: alexvs11 16.2.2011, 23:51 |
| студийный stl должен быть потокобезопасным, зато в коде есть ошибка [0 1 2 ->3] после erase [0 1 2 ->] ++it ? |
| Автор: nerdy_weirdie 17.2.2011, 00:12 |
| Спасибо за ответ! Что-то не нахожу ошибку. После erase идет break; и итератор не инкрементируется. |
| Автор: alexvs11 17.2.2011, 00:25 |
| да, извините, осмотрелся попробуйте поставить на входе в метод дебажный вывод, чтоб посмотреть кто перед ошибкой приходит, и правильно ли работает критическая секция а что SAFEDEL делает? еще в критических секция должны быть все куски кода, где идет доступ к его содержимому |
| Автор: volatile 17.2.2011, 00:28 | ||
Напишите так:
|
| Автор: alexvs11 17.2.2011, 00:31 |
| volatile, по break'у он из цикла выйдет |
| Автор: volatile 17.2.2011, 00:36 |
Упс, да действительно, сорри. туплю Но в любом случае возможно он дальше используется. и наследовать от STL классов, еще раз, очень не рекомендуется. |
| Автор: nerdy_weirdie 17.2.2011, 00:49 |
| Спасибо за советы, разобрался. Как раз дебажный вывод и обращался по невалидному итератору )) но дебагер почему-то тыкал меня в совершенно другую строку. Модератор, удалите пожалуйста тему |
| Автор: azesmcar 17.2.2011, 07:49 | ||
с каких это пор? |
| Автор: borisbn 17.2.2011, 10:14 | ||
volatile, много раз слышал это из разных источников, но не могу понять, почему именно ? Спасибо. чевойта ? |
| Автор: Alexeis 17.2.2011, 10:49 |
Вот и я не пойму. Он потокобезопасен если много читают и никто не пишет. Если хоть кто-то пишет но ни какой потокобезопаности. |
| Автор: azesmcar 17.2.2011, 10:54 | ||
Вообще-то стандарт C++ даже в этом случае не гарантирует безопасности, вдруг какой нибудь умник взял и написал модифицирующий код в read-only функции. Вряд ли конечно, но чем черт не шутит..В общем случае конечно можно полагаться на современные реализации и считать, что чтение потокобезопасно, но только чтение. Ну да. Такого вообще быть не может, ведь потокобезопасность контейнера здорово снижает его производительность. Никто не станет делать потокобезопасным все контейнеры. Максимум делают две версии. |
| Автор: baldina 17.2.2011, 15:03 | ||||||
проще std::list::remove_if():
|
| Автор: borisbn 17.2.2011, 15:09 |
| baldina, в твоём случае удаляться все элементы, а в варианте с while - только первый, т.к. там стоит break; |
| Автор: alexvs11 17.2.2011, 15:42 | ||
это обозначает, что в многопоточной среде в условиях когда доступ к объектам stl'a идет раздельно ничего само не взорвется
|
| Автор: Abyx 17.2.2011, 15:54 |
| alexvs11, и какое нам дело до "The SGI implementation of STL" ? |
| Автор: azesmcar 17.2.2011, 15:59 | ||||||
| alexvs11 1. В visual C++ (по умолчанию) стоит http://www.dinkumware.com/, а не SGI. 2.
это означает, что доступ к разным контейнерам, разными потоками безопасен (еще бы, только этого нам не хватало
чтение общих контейнеров потокобезопасно, это гарантия реализации от SGI, тем не менее стандарт такой гарантии не дает.
Вот он! Контейнер потокобезопасен для чтение, но не для записи. Если мы вернемся к исходнику в первом посте, мы увидем, что ТС пытается удалить элемент из контейнера, что никак нельзя назвать чтением. |
| Автор: borisbn 17.2.2011, 15:59 | ||||
и к std::istream ? если говорить только о SLT-контейнерах, то понятно, что вызsвать функции для чтения можно из разных потоков, правда никто не гарантирует, что сами потоки не будут изменять содержимое. Например, если вызывать ф-цию begin() из разных потоков, то она гарантировано вернёт одно и то же, если же в самом потоке писать в этот инетратор, то ...
так что говорить, что некорректно в студии используют Hewlett-Packard implementation, насколько я знаю. |
| Автор: alexvs11 17.2.2011, 16:01 | ||||
вы не поверите |
| Автор: azesmcar 17.2.2011, 16:03 |
| alexvs11 Заметье, я ничего не писал по поводу второго сообщения. Я возразил против первого. Или вы продолжаете утверждать, что студийная реализация STL потокобезопасна? |
| Автор: alexvs11 17.2.2011, 16:06 | ||||||
они прародители стандартного стла, привык читать маны оттуда, согласен что он не является стандартным на текущий момент http://www.sgi.com/tech/stl/ внизу подпись
между прочем Добавлено @ 16:11
я неправильно выразился, этим имел в виду, что если синхронизация правильная, то проблемы у автора, а не у stl'a а в многопоточной среде бывает что и при синхронизации работает не так, взять тот же небезопасный CreateThread и безопасный _beginthread |
| Автор: mes 17.2.2011, 16:34 | ||
потому что исполнение стандартных контейнеров является логически финальной и расшить/изменить интерфейс не нарушив логической полноценности является трудно выполнимой задачей.. поэтому в общем случае их не рекомендует наследовать, особенно не приватно.. |
| Автор: alexvs11 17.2.2011, 16:49 |
| кстати, методы контейнера ведь и не обязаны быть виртуальными, правильно я понимаю? тогда это вообще лишает принципиального смысла наследование - подсунуть под указателем list уже не удастся, а схожесть интерфейса решится обычным делегированием |
| Автор: borisbn 17.2.2011, 16:58 | ||||
а почему, если я добавлю в deque такие ф-ции
я "нарушу локическую полноценность" ? mes, если не сложно, можете на конкретном примере пояснить, почему же наследоваться от stl - не есть хорошо ? Объяснение "а вот тут ты сам можешь потом забыть и (не)использовать эту штуку" - принимаются. Спасибо. |
| Автор: baldina 17.2.2011, 16:59 | ||
да, так. хотя телепатия подсказала что break там скорее для оптимизации. |
| Автор: mes 17.2.2011, 17:10 |
| Добавлено @ 17:11 перенесено в соответствующую тему.. |
| Автор: alexvs11 17.2.2011, 17:19 |
| borisbn, концептуально наследование должно использоваться для специализации одной сущности к другой, общему deque к конкретному MyDeque, так чтобы конкретный MyDeque мог использоваться как специализированный MyDeque и как общий deque но тут возникают две концептуальные проблемы 1) стандартный deque не предназначен для специализации ( отсутствие виртуальных функций, protected полей итп ). 2) само отсутствие виртуальных функций делает невозможное использование вашего MyDeque как общего deque там где наследование не приносит много пользы обычно используют агрегирование, тк дает те же результаты и связанность между классами будет меньше (при наследовании всегда железная связонность) |
| Автор: mes 17.2.2011, 17:23 |
тут больше подходит не "связанность", а "сцепление" или "зависимость".. |
| Автор: borisbn 17.2.2011, 18:18 | ||
согласен на 99,9(9). http://forum.vingrad.ru/forum/topic-322803.html |
| Автор: baldina 17.2.2011, 18:38 | ||
borisbn, есть признак: если деструктор не виртуальный, то класс не предназначен для наследования
а никто не говорил, что в данном случае что-то нарушится в этих функциях ничего страшного нет: они бесполезны, т.к. не расширяют семантику класса. а как только понадобится захочется создать действительно специализированную версию контейнера (путем наследования), начнутся проблемы: стандартные контейнеры не являются абстрактными классами с точки зрения языка: виртуальные функции использовать нельзя (деструктор невиртуальный), и функции доступа невиртуальные с другой стороны, стандартные контейнеры являются АТД, и в этом смысле их расширять не требуется. с третьей: если, скажем, нужно создать стек на основе списка, заимствуя при этом часть функций, технически удобно использовать наследование, но - закрытое. т.е. применить прием С++, не относящийся к ООП. кстати в stl стек так и сделан. еще пример: паттерны типа Facade и Adapter(Wrapper) решаются путем агрегирования или закрытого наследования, а полученный класс также не предназначен для наследования Добавлено через 2 минуты и 27 секунд ща поглядел, и вижу, что нет: стек агрегирует контейнер. а мне казалось я где-то видел закрытое наследование... |
| Автор: mes 17.2.2011, 19:15 |
| перенесено Abyx, автор оффтопика уже создал отдельную тему... |
| Автор: Abyx 17.2.2011, 19:39 | ||
лолшто? вообще-то есть статический полиморфизм, aka CRTP, и местами его очень много. |
| Автор: alexvs11 17.2.2011, 20:07 |
в указанном примере не было речи о привлечении каких-либо дополнительных идиом так что все в рамках приличия |
| Автор: ValeryLaptev 20.2.2011, 11:16 | ||||
Не рекомендуется наследовать, так как в стандартных контейнерах деструктор НЕ ЯВЛЯЕТСЯ ВИРТУАЛЬНЫМ. |
| Автор: mes 20.2.2011, 11:58 | ||
так громко потому что это забыли упомянуть ? нет уже говорили.. или потому что это главная причина ? опять же нет, далеко не первая.. так позвольте узнать , что хотелось подчеркнуть криком ? |
| Автор: azesmcar 20.2.2011, 12:36 | ||
Если только это, то это вообще не причина НЕ наследовать, это причина не удалять объект через указатель на базовый класс. Для ясности: я не согласен с тем, что класс, который наследуется обязан иметь виртуальный деструктор. Я считаю, что класс, который имеет хоть одну виртуальную функцию, должен иметь виртуальный деструктор. Остальное должно решаться в зависимости от ситуации. И кстати обсуждение переехало http://forum.vingrad.ru/forum/topic-322803/0.html. |