Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > Общие вопросы .NET
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 29.03.2018, 03:13   #1
OmegaBerkut
Спокойный псих
Участник клуба
 
Аватар для OmegaBerkut
 
Регистрация: 19.03.2013
Сообщений: 1,538
По умолчанию Ошибка с повреждением памяти процесса (C#)

Здравствуйте. Я на форуме уже спрашивал по поводу этой ошибки, но не обнаружил тему в списке созданных мною.

Скриншот ошибки прикрепил.
Из-за чего могут вообще появляться такие ошибки ? Помимо варианта криворукости автора; это я и пытаюсь исправлять.
В гугле у всех по разному, но в основном у всех "проблемы с массивом".
Я же для теста исключил содержание объектов в массивах, но как водится, проблема не исчезла.
Задача программы - обеспечивать хаотичное (не синхронизированное) поведение объектов (игра по типу Tower Defence - перемещение, наведение, стрельба, ну и так далее, проблемы теперь на стрельбе).

По большому счёту, программа падает просто потому что потоки не синхронизированы, ну это как я понял. Но мне и не нужно их синхронизировать, так как у каждого объекта своя цель, и выполнение не должно зависеть от поведения соседних объектов.
И всё же, я решил забавы ради кинуть неуправляемую (lock) синхронизацию на главный поток процесса (интерфейс, окно программы), и получил завершение программы с кодом 0x4000001f в отладчике. То есть программа теперь просто падает, без возможности узреть место-время-причину ошибки. То самое чувство, когда осознаёшь, что ошибка не в коде, хотя технически это всё равно не так.

Пока что ввёл динамическое ограничение: чем больше выстрелов "в полёте" - тем дольше задержка перед следующим выстрелом (для всех стреляющих). И пока вроде даже держится.

P. S. Здесь уже не важно, как именно я реализую много-поточность, любая реализация с таким подходом должна и будет падать, видите ли, "система на что то там не рассчитана". Ну и я дурак. Может что то не так понял ?
Что то я приуныл, пойду посплю.

Что вы можете подсказать ? Эта тема больше подходит для форума "свободное общение", но тематика всё же решает
Изображения
Тип файла: png lol.png (27.9 Кб, 124 просмотров)
Подпись ? Не, не слышал ...
OmegaBerkut вне форума Ответить с цитированием
Старый 29.03.2018, 07:32   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Скорее всего вы пытаетесь нарисовать что-то, что уже уничтожилось в соседнем потоке. Обычно не синхронизируют логику, цели потоков и т.д. Синхронизируют общие ресурсы, например, список объектов для отрисовки.
p51x вне форума Ответить с цитированием
Старый 29.03.2018, 08:02   #3
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,520
По умолчанию

Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Задача программы - обеспечивать хаотичное (не синхронизированное) поведение объектов (игра по типу Tower Defence - перемещение, наведение, стрельба, ну и так далее, проблемы теперь на стрельбе).

По большому счёту, программа падает просто потому что потоки не синхронизированы, ну это как я понял. Но мне и не нужно их синхронизировать, так как у каждого объекта своя цель, и выполнение не должно зависеть от поведения соседних объектов.
Перечитывайте про синхронизацию в многопоточном программировании.
Смысл синхронизации в том, чтобы не ломать общие ресурсы и получать правильные данные. Поведение объектов может быть хоть хаотичным, хоть одинаковым, вообще никакого отношения к синхронизации не имеет. Если они где-то хранятся в общей коллекции, то нужно эту коллекцию делать thread-safety.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
И всё же, я решил забавы ради кинуть неуправляемую (lock) синхронизацию на главный поток процесса (интерфейс, окно программы), и получил завершение программы с кодом 0x4000001f в отладчике. То есть программа теперь просто падает, без возможности узреть место-время-причину ошибки. То самое чувство, когда осознаёшь, что ошибка не в коде, хотя технически это всё равно не так.
Ага. Положил на крышу разваливающегося дома лист подорожника, но кирпичи продолжают падать на голову, странно.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Пока что ввёл динамическое ограничение: чем больше выстрелов "в полёте" - тем дольше задержка перед следующим выстрелом (для всех стреляющих). И пока вроде даже держится.
Это сплошная лотерея. В следующий раз потоки обработаются в другом порядке и всё рухнет.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Что вы можете подсказать ? Эта тема больше подходит для форума "свободное общение", но тематика всё же решает
Читать про особенности многопоточной разработки.
pu4koff вне форума Ответить с цитированием
Старый 29.03.2018, 09:40   #4
OmegaBerkut
Спокойный псих
Участник клуба
 
Аватар для OmegaBerkut
 
Регистрация: 19.03.2013
Сообщений: 1,538
По умолчанию

Цитата:
Сообщение от pu4koff Посмотреть сообщение
Положил на крышу разваливающегося дома лист подорожника, но кирпичи продолжают падать на голову
Спасибо за формулировку, поржал с просонья =)

Цитата:
Сообщение от p51x Посмотреть сообщение
Скорее всего вы пытаетесь нарисовать что-то, что уже уничтожилось в соседнем потоке.
Когда у меня появились проблемы с общими ресурсами ("ресурс занят другим процессом") - я начал их клонировать (innerImg=(Image)inputImg.Clone();), тогда проблема уменьшилась до места клонирования, я развесил lock'и и проблема "с общими ресурсами" считалась исчерпанной.
Но при таком поведении, ресурсы нужно же освобождать, чем я и занимаюсь в Dispose/Finalize (innerImg.Dispose();). Я конечно же могу возложить болта на регулярно-хаотичное выделение памяти, и пускай этим занимается GC. Но я не очень уверен в том, что это поможет ... Ресурсы то "разбросаны", а моя общая проблема проявляется при постоянно-быстрой работе объектов. И действительно, это происходит именно в этом моменте:
Цитата:
Сообщение от p51x Посмотреть сообщение
вы пытаетесь нарисовать
Но в данных отладки при падении все данные объекта вроде как даже целые.

Цитата:
Сообщение от pu4koff Посмотреть сообщение
Если они где-то хранятся в общей коллекции, то нужно эту коллекцию делать thread-safety.
У меня ссылки на объекты добавляются в List<Enemy/Shot>, всё под тем же lock, и так же оттуда удаляются.
Код:
lock (field.Shots) field.Shots.Add(this);
// ...
lock (field.Shots) field.Shots.Remove(this);
Но это не удаление самого объекта, а обрабатывающие потоки находятся в самих объектах.
Что тут может быть не так ?
Подпись ? Не, не слышал ...

Последний раз редактировалось OmegaBerkut; 29.03.2018 в 10:05.
OmegaBerkut вне форума Ответить с цитированием
Старый 29.03.2018, 10:35   #5
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,520
По умолчанию

Не так тут архитектура сделана. Не те объекты не тем занимаются и всё это в многопоточности. Не знаю откуда взялось стремление каждый выстрел выделить в отдельный поток, но подозреваю, что там в целом подход неправильный и игра работает не так, как нужно (одному потоку досталось больше процессорного времени и снаряд дальше улетел, другой дольше спал и снаряд завис на месте).
Для начала хотя бы однопоточный вариант нужно сделать, чтобы всё правильно работало, а потом уже пытаться распараллелить, если вообще это нужно будет.
pu4koff вне форума Ответить с цитированием
Старый 29.03.2018, 10:41   #6
OmegaBerkut
Спокойный псих
Участник клуба
 
Аватар для OmegaBerkut
 
Регистрация: 19.03.2013
Сообщений: 1,538
По умолчанию

Цитата:
Сообщение от pu4koff Посмотреть сообщение
откуда взялось стремление каждый выстрел выделить в отдельный поток
Вариант с неравномерным разделением процессорного времени получается менее тормознутым. Чем больше выстрелов будет обрабатывать один поток - тем дольше будет работать собственно поток.
При условных 30 маленьких потоках неравномерность разделения процессорного времени получается незначительна, и общая скорость выполнения остаётся визуально в пределах нормы.

Однопоточный вариант работает нормально, но как я и сказал, когда я начал напихивать в него больше выстрелов - время прохождения маршрута растёт прямо пропорционально количеству выстрелов. Отсюда и разделение на потоки.
Подпись ? Не, не слышал ...
OmegaBerkut вне форума Ответить с цитированием
Старый 29.03.2018, 12:15   #7
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,520
По умолчанию

На сколько я знаю, в играх делается так:
засекается время с предыдущего отображения сцены.
пересчитываются координаты снарядов с учётом этой дельты.
допустим, у нас снаряд летит 10 метров/с, у нас прошла 1 секунда, смещаем снаряд на 10 метров. прорисовываем изменённую сцену.
в процессе обработки сцены соответственно можно параллельно пересчитать координаты всех выстрелов и всё, что можно распараллелить.
иначе получится, что на мощных компах слишком быстро играется, на слабых - черепашья скорость и вообще баланс игры не выстроишь никак.
В общем, гуглим "игровой цикл" и делаем как у других. Это с ошибкой из первого сообщения никак не связано, но текущую реализацию я бы не допиливал, ибо она утопична.
pu4koff вне форума Ответить с цитированием
Старый 29.03.2018, 12:27   #8
OmegaBerkut
Спокойный псих
Участник клуба
 
Аватар для OmegaBerkut
 
Регистрация: 19.03.2013
Сообщений: 1,538
По умолчанию

Цитата:
Сообщение от pu4koff Посмотреть сообщение
на мощных компах слишком быстро играется, на слабых - черепашья скорость
Ну вообще то так было всегда. Только в сурьйозных играх ещё графоний вешает и греет систему.
Что касается конкретно текущей реализации - описанная вами ситуация будет проявляться при больших количествах объектов, что как ни странно, нормальное явление для любой серьёзной и не очень игры.

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

Цитата:
Сообщение от pu4koff Посмотреть сообщение
текущую реализацию я бы не допиливал, ибо она утопична
Хм ... Как то абстрактно выглядит. Чего утопичного то (?)


Цитата:
Сообщение от pu4koff Посмотреть сообщение
Это с ошибкой из первого сообщения никак не связано
Возвращаясь к своей ошибке ... Я её раньше решал перепиливанием ресурсов.
Сейчас это не спасает.
Убрал код, отвечающий за принудительное освобождение ресурсов (повесил на GC.Collect();), убрал "самоизвлечение" объекта из коллекции, так же дописал код, отвечающий за удаление ссылок из массива в отдельном игровом потоке.

Проблема не исчезла. Из чего можно сделать преинтереснейший вывод, что некто истребляет данные объекта до того, как поток объекта завершит работу. Кстати, у Graphics в месте падения оказывается куча Exceptions внутри.

Думал, что проблема находится где то в районе попыток самоуничтожения потока (предполагалось, что поток сам выпилит все следы существования объекта-носителя), но - я перепилил на флаги состояния + уничтожение из-вне потока и объекта, и как всегда, проблема осталась во всей красе.
Прикол этой ошибки в том, что при её возникновении программа вообще теряет возможность выполнять что либо и где либо. Это исключение можно поймать в обработку только со специальными ухищрениями (правки App.config), когда я научил программу обрабатывать именно это исключение - программа вешалась целиком и полностью (в этом и отражается название темы).

Дальше про потоки.
Так же, метод Thread.Abort() всё равно приходится вызывать, даже после того, как поток вышел за пределы функции - он всё ещё
IsAlive && ThreadState.Running && !ThreadState.Stopped && !ThreadState.Suspended
короче, независимо от настроения Аллаха, положения звёзд планет астероидов и Луны, поток никак и никогда не завершается без аборта оного, и если IsBackgound==false - вся программа не сможет самостоятельно и честно закрыться. Но во избежание проблем с отладкой всё равно приходится вешать флаги, и ждать завершения выполнения функции, а только после пускать аборт.

Что-что, а на плюсиках с потоками было хоть и муторнее, но всё же проблем таких не было (я и рисовал в MFC, правда без нагрузочных тестов), а тут от плевка в сторону Graphics по велению того самого некто вешается и сыпется всё.
Подпись ? Не, не слышал ...
OmegaBerkut вне форума Ответить с цитированием
Старый 29.03.2018, 12:50   #9
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,520
По умолчанию

Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Ну вообще то так было всегда. Только в сурьйозных играх ещё графоний вешает и греет систему.
Так было лет 30 назад. Особо хорошо косяки проявлялись в сетевых играх. Обидно будет, что человек с более мощным компьютером всех обыграет в гонке, т.к. быстрее сцена отсчитывается и машина из-за этого быстрее едет.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Что касается конкретно текущей реализации - описанная вами ситуация будет проявляться при больших количествах объектов, что как ни странно, нормальное явление для любой серьёзной и не очень игры.
Пришло человеку сообщение в скайпе - какой-нибудь снаряд подотстал, процессор решил, что нужно частоту увеличить - опять разрыв пошел, планировщик операционки как-то перестроил очередь потоков - опять погрешность. Так что будет проявляться при куче условий.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Если у каждого снаряда своя скорость движения, т. е. своё время задержки потока, то при "нормальных" условиях всё же нормально должно быть ...
Windows не является системой реального времени и всё это относительно. Время задержки потока указывает, что поток заснёт не менее, чем на такое время, а по факту оно может быть сильно больше.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Хм ... Как то абстрактно выглядит. Чего утопичного то (?)
Допустим у нас 50 выстрелов. Мы для них создаём 50 неуправляемых потоков. На каждый поток ОС тратит ресурсы и определяет какому из них сейчас дать время поработать.
Вместо этого я предлагаю написать простой цикл foreach или Parallel.ForEach и в нём посчитать новые координаты снарядов. Никаких переключений контекстов и т.п. И быстрее и правильнее.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Возвращаясь к своей ошибке ... Я её раньше решал перепиливанием ресурсов.
Общие ресурсы делаются только для чтения и их не нужно синхронизировать/клонировать. Если нам нужно нарисовать 50 одинаковых пуль, то берём из общей коллекции Image и рисуем его 50 раз в нужных местах без какой-либо синхронизации.
Цитата:
Сообщение от OmegaBerkut Посмотреть сообщение
Убрал код, отвечающий за принудительное освобождение ресурсов (повесил на GC.Collect();), убрал "самоизвлечение" объекта из коллекции, так же дописал код, отвечающий за удаление ссылок из массива в отдельном игровом потоке.

Проблема не исчезла. Из чего можно сделать преинтереснейший вывод, что некто истребляет данные объекта до того, как поток объекта завершит работу. Кстати, у Graphics в месте падения оказывается куча Exceptions внутри.

Думал, что проблема находится где то в районе попыток самоуничтожения потока (предполагалось, что поток сам выпилит все следы существования объекта-носителя), но - я перепилил на флаги состояния + уничтожение из-вне потока и объекта, и как всегда, проблема осталась во всей красе.
Прикол этой ошибки в том, что при её возникновении программа вообще теряет возможность выполнять что либо и где либо. Это исключение можно поймать в обработку только со специальными ухищрениями (правки App.config), когда я научил программу обрабатывать именно это исключение - программа вешалась целиком и полностью (в этом и отражается название темы).

Дальше про потоки.
Так же, метод Thread.Abort() всё равно приходится вызывать, даже после того, как поток вышел за пределы функции - он всё ещё
IsAlive && ThreadState.Running && !ThreadState.Stopped && !ThreadState.Suspended
короче, независимо от настроения Аллаха, положения звёзд планет астероидов и Луны, поток никак и никогда не завершается без аборта оного, и если IsBackgound==false - вся программа не сможет самостоятельно и честно закрыться. Но во избежание проблем с отладкой всё равно приходится вешать флаги, и ждать завершения выполнения функции, а только после пускать аборт.

Что-что, а на плюсиках с потоками было хоть и муторнее, но всё же проблем таких не было (я и рисовал в MFC, правда без нагрузочных тестов), а тут от плевка в сторону Graphics по велению того самого некто вешается и сыпется всё.
Это называется: отсутствие понимания как всё это работает, попытки методом тыка решить проблему усложняя решение задачи и еще глубже закапываясь.
Есть проверенный временем подход с игровым циклом, не нужно ничего усложнять и изобретать велосипед. В Windows оконные приложения подобным образом работают, так же цикл и т.д. и т.п.
pu4koff вне форума Ответить с цитированием
Старый 29.03.2018, 13:08   #10
OmegaBerkut
Спокойный псих
Участник клуба
 
Аватар для OmegaBerkut
 
Регистрация: 19.03.2013
Сообщений: 1,538
По умолчанию

Цитата:
Сообщение от pu4koff Посмотреть сообщение
Общие ресурсы делаются только для чтения и их не нужно синхронизировать/клонировать
Что интересно, одновременное чтение ресурса ссылочного типа всё равно не допускается. То есть, минимум lock всё равно нужен.

Зато я смог сделать, что бы при выпадении этого исключения программа элегантно вызывала GetCurrentProcess().Kill().
Подпись ? Не, не слышал ...
OmegaBerkut вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Поиск в памяти процесса Mr_ViK Общие вопросы Delphi 5 27.08.2012 21:38
Редактирование памяти процесса Dima DDM Общие вопросы Delphi 0 25.12.2010 16:54
Размер памяти процесса ZaRDaK Общие вопросы Delphi 5 25.09.2010 23:48
Редактирование памяти процесса Air Win Api 6 16.02.2008 20:15