У меня проблемы с одновременным использованием общей коллекции в многопользовательской синхронной игре, над которой я работаю. Я немного покопался и нашел аккуратную поточно-ориентированную реализацию IEnumerator / IList в посте Алексея Дробышевского о проекте кода здесь:
http://www.codeproject.com/KB/cs/safe_enumerable.aspx
После принятия его реализации я даже заменил все запросы Linq в общей коллекции на циклы for / foreach, потому что запросы Linq все еще использовали небезопасный IEnumerable под ним.
Вот моя реализация SafeList, и сам список представляется как ReadOnlyCollection для потребляющих классов.
http://theburningmonk.com/2010/03/thread-safe-enumeration-in-csharp/
После перехода к этому списку SafeList я вижу гораздо меньше проблем, но при большой нагрузке (80+ потоков, все из которых читают / пишут из и в список в разных точках), я по-прежнему вижу исключение InvalidOperationException:
Список элементов изменился. Не удалось продолжить операцию перечисления
Я даже пытался использовать ReadWriterLockSlim вместо объекта блокировки в моей реализации SafeList, но это также оказалось бесплодным. Единственное другое предложение, которое у меня было до сих пор, - это клонирование списка каждый раз, когда потоки должны пройти по нему. Я надеюсь избежать клонирования списка каждый раз, так как список используется слишком часто, это может привести к снижению производительности и появлению других ошибок, которые трудно обнаружить.
Учитывая временные ограничения, я должен быть прагматичным в этом вопросе, и если клонирование является самым безопасным и быстрым способом решения этой проблемы, то я в порядке, но перед тем, как прибегнуть к последней попытке рва, я ' Мне просто интересно, если кто-нибудь сталкивался с чем-то подобным, может дать какой-то совет.
Заранее большое спасибо!
[РЕДАКТИРОВАТЬ] Вот немного больше информации о проблеме, которую я вижу по запросу:
Для одной «игры» может быть подключено до 100 или более синхронных клиентов, и игра должна сообщать каждому подключенному клиенту обновления каждые несколько секунд, и поэтому каждые несколько секунд этой игре необходимо перебирать общий список игроков. ,
Когда игрок присоединяется или уходит, список необходимо обновить соответствующим образом, чтобы отразить изменения.
Чтобы добавить к этому, игроки могут взаимодействовать с игрой и общаться в чате с другими игроками, и каждый раз, когда от игрока поступает сообщение, игре снова приходится повторять один и тот же список и выполнять трансляцию.
Исключения обычно генерируются, когда игра пытается передавать сообщения игрокам (операция чтения) в то же время, когда многие игроки покидают / присоединяются (операция записи) одновременно.