8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|||||||||||
1 | |||||||||||
Удаление элемента из списка std::list в цикле01.11.2020, 13:18. Показов 6543. Ответов 17
Доброго времени суток!
*проверил подобные темы на форуме, но нормального ответа на свой вопрос так и не нашел. Гугл тоже решил лишь часть проблемы. Есть список структур std::list<Contact>. С ним работают 2 потока: 1-й поток добавляет элементы, 2-й - удаляет. Удаление происходит по условию if Код
if (iter->sthread != ThreadState::WORK) Сначала я сделал так:
Нагуглил другой вариант: заменить Contacts.remove(*iter) на Contacts.erase(iter), но теперь вылетала ошибка "cannot increment value-initialized iterator". Так же пробовал заменить цикл for на while (тоже нагуглил такой вариант):
Я студент, делаю лабу - многопоточный сервер на WinSock, но C++ как таковой мы не учили в принципе (ну, вы понимаете: знать синтаксис, пару функций Си и знать C++ - огромная разница). Когда подключается клиент, данные о нем заносятся в список, а когда отключается - элемент этого клиента помечается как "для удаления" (sthread элемента = что угодно, кроме WORK), и поток должен постоянно проверять список и удалять уже ненужные элементы. Объясните, пожалуйста, как это сделать по-человечески? Уже чувство, что я вообще перестал понимать, как устроен этот чертов список. Заранее спасибо!
0
|
01.11.2020, 13:18 | |
Ответы с готовыми решениями:
17
Std::list удаление элемента во время цикла Удаление элемента списка list.STL Удаление элемента из списка List<T> (Удалить счет по по названию из указанного клиента) Непосредственное удаление из std::list |
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
|
|
01.11.2020, 14:12 | 2 |
Где вылетает? Какую конкретно строчку отладчик подсвечивает? Сделайте минимальный тестовый пример, воспроизводящий ошибку. А то может, она вообще в совсем другом месте (и совсем не обязательно, сразу себя проявляет).
Добавлено через 5 минут А, стоп, это все объясняет. Ключевое слово - "многопоточный". Синхронизацию доступа к глобальным объектам организовали, мютексты расставили? Если нет, то в многопоточной среде все и будет падать в произвольные моменты, по неясным причинам. C++ контейнеры сами по себе многопоточность не поддерживают.
0
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
||||||
01.11.2020, 15:14 [ТС] | 3 | |||||
Синхронизация есть, в каждом способе делал критическую секцию. В последнем примере ее нет, но и с ней все равно все падает. Не уверен, но я очень сомневаюсь, что проблема в многопоточном доступе к списку - все синхронизировано с помощью критических секций.
Вот, сделал. Ошибка "list iterators incompatible". В ходе моих проб и ошибок она тоже выскакивала в проекте сервера. Кликните здесь для просмотра всего текста
Добавлено через 5 минут Еще пару раз запустив этот код, также вылезла и ошибка "cannot increment value-initialized list iterator". Кстати говоря, когда я пробовал делать эту ситуацию без многопоточности (в main() сначала добавил 1 элемент в список, а затем удалил его в цикле), ошибок не было вовсе. Неужели ошибка действительно где-то из-за многопоточности?
0
|
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
|
|
01.11.2020, 15:27 | 4 |
У вас синхронизация сделана только при записи. Это не исключает состояния гонки "один поток читает, а другой в это время перезаписывает".
Алсо, в C++ синхронизация делается через std::mutex. А потоки создаются через std::thread. Дергать WinAPI тут не нужно.
0
|
01.11.2020, 15:44 | 5 |
Создавать итераторы, вызывать empty() и size() тоже надо под защитой так как другой поток может в этот момент добавлять/ удалять из листа
Добавлено через 1 минуту removeFlag должен быть std::atomic_int так как в с++ даже запись в bool не факт что атомарно
1
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
||||||
01.11.2020, 15:52 | 6 | |||||
Сообщение было отмечено Ivanshka как решение
Решение
Не очень понял, что ты пытаешься сделать, но в твоём случае только вот так
1
|
2784 / 1937 / 570
Регистрация: 05.06.2014
Сообщений: 5,602
|
||||||
01.11.2020, 15:55 | 7 | |||||
Сообщение было отмечено Ivanshka как решение
Решение
Ну и совсем по плюсовски:
1
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
||||||
01.11.2020, 16:04 | 8 | |||||
Сообщение было отмечено Ivanshka как решение
Решение
Что-то типа
1
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|
01.11.2020, 16:23 [ТС] | 9 |
Да, я уже сам методом проб и ошибок понял, что нужно более "глобально" блокировать. Потом проверил здесь ответы, оказалось, прав) Большое спасибо за ваши примеры!)
Разобрался, спасибо большое за помощь!)
0
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
01.11.2020, 16:27 | 10 |
Используй всё-таки std::mutex и std::lock_guard/unique_lock, вместо EnterCriticalSection/LeaveCriticalSection и д.р. Не забывай, что могут возникнуть исключения, exceptions.
0
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|
01.11.2020, 16:32 [ТС] | 11 |
oleg-m1973, да, я заменил секции на мьютексы. И подумываю заменить потоки WinAPI на std::thread (если получится, а то я пока не знаю, мб по лабе нужно будет приостанавливать поток, а std::thread так не умеет). Все же лучше полагаться "на сам язык", на STL, чем на WinAPI (грубо говоря). Трудно студенту-шарписту писать на плюсах, трудно(
Спасибо за совет!
0
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
01.11.2020, 16:35 | 12 |
Умеет. Все функции из WinAPI прекрасно работают с std::thread.
Покажи задание.
0
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|
01.11.2020, 16:41 [ТС] | 13 |
oleg-m1973, к сожалению, задание скинуть не могу: лаба состоит из 30 заданий, каждое из которых - немаленький абзац. Например, вот задание, на котором я сейчас ломался:
Кликните здесь для просмотра всего текста
Задание 17. Удалите отладочный вывод в функции GarbageCleaner и создайте цикл сканирования списка ListContact. Функция GarbageCleaner должна выявлять неиспользуемые (об этом есть соответствующая отметка, сделанная потоком DispatchServer или обслуживающим сервером) элементы списка ListContact. Запустите сервер ConcurrentServer и обеспечьте подсоединение к нему одного клиента. Убедитесь с помощью отладчика, что поток GarbageCleaner удаляет неиспользуемые элементы списка ListContact в случае успешного обслуживания клиента, в случае выдачи клиентом неправильного запроса, а также, если клиент завершился аварийно во время сеанса связи. В последнем случае может потребоваться доработка функции EchoServer.
Если вдруг заинтересовало, кину под спойлер всю лабу) XD Об этом и вовсе не знал. О_о Спасибо!
0
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
01.11.2020, 16:44 | 14 |
Здесь лучше использовать std::list::splice, чтоб твой garbage collector не блокировал намертво рабочие потоки
0
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|
01.11.2020, 17:02 [ТС] | 15 |
oleg-m1973, ага, видел, как вы использовали ее выше. Хотелось бы уточнить, как работает ваш код. Я с этой функцией не знаком (только описание сейчас прочитал), поэтому могу ошибаться.
Насколько я понял, вместо удаления (дорогого по времени), вы перемещаете ненужные элементы из основного списка в RemovedContacts, а в функции удаления снова перемещаете (опять же для производительности) в список items, который чистится на каждой итерации цикла while. Все верно?
0
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
01.11.2020, 17:05 | 16 |
Ну да, типа того. Тогда блокировка делается на константное время O(1), вместо O(N).
0
|
8 / 3 / 1
Регистрация: 11.08.2016
Сообщений: 44
|
|
01.11.2020, 17:12 [ТС] | 17 |
oleg-m1973, все, теперь понятно. Большое спасибо!
0
|
6770 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
01.11.2020, 17:16 | 18 |
Здесь я ошибся (привык работать с std::lock_guard). Этот if-continue нужно убрать, иначе будет дедлок
1
|
01.11.2020, 17:16 | |
01.11.2020, 17:16 | |
Помогаю со студенческими работами здесь
18
Удаление значения в std::list Заполнение списка std::list из буфера Инициализация элементов списка списков (List<List>) происходит одинаково для каждого элемента Переместить элемент внутри списка std::list Получение предыдущего объекта из списка (std::list) Вставка нового элемента в список, удаление элемента из списка, просмотра содержимого списка Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |