2010-06-29 2 views
1

За последние 48 часов я пытался понять Multithreading и Socket Programming. Я попытался реализовать программирование сокетов и имел успех, когда не использовал многопоточность. Я новичок в обеих темах и поднял 2-3 вопроса о том, что сам стек нуждается в помощи на том же самом.Как использовать Многопоточность, замки, Программирование сокетов

После прибегая к помощи много я нашел article что объясняет Socket Programming и Multithreading, но я до сих пор есть много сомнений в этой статье, и застрял в Figure 5 в статье.

private void AcceptConnections() 
    { 
     while (true) 
     { 
      // Accept a connection 
      Socket socket = _serverSocket.Accept(); 
      ConnectionInfo connection = new ConnectionInfo(); 
      connection.Socket = socket; 

      // Create the thread for the receives. 
      connection.Thread = new Thread(ProcessConnection); 
      connection.Thread.IsBackground = true; 
      connection.Thread.Start(connection); 

      // Store the socket 
      lock (_connections) _connections.Add(connection); 
     } 
    } 

В самой последней строке вы можете увидеть lock было принято и 3-4 строчками выше в delegate ProcessConnection связан.

На данный момент я не понимаю, как работает этот замок. Что происходит за кулисами при блокировке? Почему автор использовал блокировку здесь? Что было бы, если бы не было блокировки? Как работает процесс ProcessConnection? Что происходит одновременно?

Я запутался со всеми этими вопросами

Я знаю, что есть список вопросов здесь, но это было бы большим подспорьем, если вы могли бы мне помочь в понимании методологии работы с многопоточностью.

ответ

2

connection.Thread.Start(connection) начинает новую тему с сообщением ProcessConnection, минуя connection как аргумент state. Выполнение в текущем потоке продолжается немедленно со следующей строки, а ProcessConnection выполняется в новом потоке.

ProcessConnection получает Socket объект из ConnectionInfo объекта, переданного ему AcceptConnections и ждет, чтобы получить данные из сокета. Когда он получает данные, он перебирает все остальные объекты ConnectionInfo в коллекции connections и отправляет эти данные каждому из них в последовательности.

Итак, что работает одновременно здесь? Ну, у нас есть начальный поток (назовем его Thread 0), исполняя AcceptConnections в бесконечном цикле.И затем для каждого соединения сокетов, которое мы приняли, у нас есть поток, выполняющий ProcessConnection.

Блокировки необходимы, потому что ProcessConnection использует foreach для прокрутки известных соединений для отправки данных. Если Thread 0 должен был добавить новое соединение к коллекции, в то время как сбор будет перечислить в foreach, InvalidOperationException будет выброшен в ProcessConnection.

lock предотвращает проблему параллелизма в этом случае, но также создает потенциальную проблему с производительностью. Это не только предотвращает изменение AcceptConnections, а ProcessConnection перечисляет его. Он также предотвращает любые два потока, выполняющие ProcessConnection из перечисления коллекции в одно и то же время. Лучшим выбором в этом случае будет ReaderWriterLockSlim, который позволит нескольким потокам одновременно читать коллекцию.

+0

'замок (_connections) { Еогеасп (ConnectionInfo сопп в _connections) { если (подключ = соединение!) { conn.Socket.Send ( буфер, BytesRead, SocketFlags.None); } } } 'Это используется для трансляции одного сообщения в каждый сокет? Как объяснено в вашем втором абзаце –

+0

Отличное объяснение, в котором все точки четко указаны. Еще читайте свой ответ, взяв статью как ссылку. Вернусь к вам, когда я прочитаю ее полностью. –

+0

@ Шантану: Да, этот цикл foreach - это тот, который передает принятое сообщение всем другим сокетам. –

1

Я принимаю _connections is List<ConnectionInfo>: Списки не являются потоковыми, и этот поток добавляет элементы в этот список. Если другой поток будет удалять элемент одновременно, результаты будут непредсказуемыми. Поэтому вы должны убедиться, что ни один другой процесс не сможет получить к нему доступ, используя блокировку.

connection.Thread.Start(connection); начинает новую тему, которая начнется сразу или через некоторое время. Текущий поток (код, который вы видите здесь) не будет иметь никакого контроля над ним. Однако этот новый поток имеет объект ConnectionInfo, поэтому он будет знать, на каком сокете выполнять задачи. Пока текущий поток продолжает слушать новых клиентов, функция ProcessConnection будет обрабатывать недавно принятый клиент.

+0

приятно объяснил и THX для вашего драгоценного времени, а также. У меня есть вопрос здесь. как узнать, какой объект является потокобезопасным, а какой нет. Что произойдет, если я сделаю блокировку на _соединении для удаления элемента. Тогда я могу добавить еще один объект в тот же список одновременно. –

+0

В MSDN они обычно сообщают вам, является ли объект потокобезопасным или нет. Если они не говорят, вы должны предположить, что это не так. Вы должны использовать блокировку как при добавлении, так и при удалении элемента из списка, иначе вы можете получить неожиданные результаты. Методы 'Добавить' и' Удалить' под капотом выполняют несколько строк кода, и когда вы вызываете их одновременно, они могут кусать друг друга. Помещение блокировки вокруг него заставит один поток ждать, пока другой отпустит его блокировку, поэтому они не будут мешать друг другу. –

1

В C#, и я думаю, что в CLR в целом каждый объект может иметь связанный с ним связанный с ним monitor. Здесь _connections представляет собой коллекцию, которая, возможно, разделяется потоками, запущенными с этой самой функции (они, вероятно, удаляют соединения из коллекции, когда они завершены). Коллекции в C# по умолчанию не синхронизированы, вы должны сделать это явно, поэтому оператор lock(_connections) для предотвращения races в коллекции.

+0

Отличные ссылки. Thx –

Смежные вопросы