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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 16.10.2012, 15:02   #1
Wolf.dp
 
Регистрация: 16.10.2012
Сообщений: 4
По умолчанию Не блокируется поток в клиент-серверном приложении (чат)

Всем доброго дня!

На лабораторной (да я студент) задали реализовать чат. В ходе реализации решил использовать асинхроный метод приема данных от клиента, и путём вызова событий обрабатыват их (например при приходе текстового сообщения от клиента вызывается событие getTextMs). Также на серверной части хранится список всех подключёных пользователей (для рассылки полученых сообщений).

При любом обращении к списку пользователей я использую lock чтобы не вылететь из перечисления. Например когда пользователь выходит из сети, то вызывается функция которая удаляет его из списка, и если другой поток в это время рассылал данный - выходит не очень красиво.

Собственно проблема - указаный элемент в lock не блокируется. И когда я запускаю к примеру сразу десять окон и одновременно их отключаю - сервер вылетает с InvalidOperationException Collection was modified; enumeration operation may not execute. (то есть у меня во время перечисления this.clientList изменился).

Код:
Код C#
        private readonly Object locker = new Object();
...
        private void client_getExit(object sender, ExitEventArgs e)
        {
            ServerClient client = sender as ServerClient;
            lock (this.locker)
            {
                this.clientList.Remove(client);
                if (client.IsAuthorization) 
                {
                    //рассылка всем пользователям, что клиент вышел из сети.
                    OutServerMessage serverMessage = new OutServerMessage(client.Id);
                    foreach (ServerClient serverClient in this.clientList)
                    {
                        serverClient.SendMessage(serverMessage);
                    } 
                }
            }
        }
this.clientList - список всех подключенных пользователей.
serverMessage - сообщение, которое отправляется на клиент.
serverClient.SendMessage - отправление текущего сообщения пользователю.

Я сначала думал, что всё это каким-то чудом висит в одном потоке, но проверка по System.Threading.Thread.CurrentThre ad.ManagedThreadId показала разные числа (надеюсь то смотрел).

также решил ради "шутки" добавить ещё одну переменную и посмотреть в дэбаге, при ошибке

Код:
Код C#
        private readonly Object locker = new Object();
        int kso = 0;
...
        private void client_getExit(object sender, ExitEventArgs e)
        {
            ServerClient client = sender as ServerClient;
            lock (this.locker)
            {
                this.kso++;
 
                this.clientList.Remove(client);
                if (client.IsAuthorization) 
                {
                    //рассылка всем пользователям, что клиент вышел из сети.
                    OutServerMessage serverMessage = new OutServerMessage(client.Id);
                    foreach (ServerClient serverClient in this.clientList)
                    {
                        serverClient.SendMessage(serverMessage);
                    } 
                }
 
                this.kso--;
            }
        }
так вот... переменная this.kso при вылавливании ошибки показывала от 2 до 5.

P.S. Пожалуйста, отзовитесь люди! Я уже второй день с этой ошибкой воюю... ='(
Wolf.dp вне форума Ответить с цитированием
Старый 16.10.2012, 17:33   #2
Скарам
Дружите с Linq ;)
Форумчанин
 
Аватар для Скарам
 
Регистрация: 15.10.2008
Сообщений: 822
По умолчанию

Что есть clientList и как он объявлен. Как List<ServerClient>? Нужно обеспечить неизменность коллекции во време foreach, скопировав List в локальную переменную
Код:
foreach (ServerClient serverClient in this.clientList.ToList())//можно this.clientList.ToArray()
                    {
                        serverClient.SendMessage(serverMessage);
                    }
Костыль, но думаю, что спасет.
Не давай организму поблажки, каждый день тренируй его в шашки..
Скарам вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
проблемы в клиент серверном приложении vangog C# (си шарп) 0 11.09.2011 19:59
Чат клиент-сервер pavelslap PHP 0 06.12.2010 20:49
FibPlus в клиент-серверном приложении Rusland Работа с сетью в Delphi 0 13.04.2010 14:04
Чат-клиент на С++ VanHelsing Общие вопросы C/C++ 0 21.01.2010 10:23