Что может произойти в двух одновременных вызовах NetworkStream.BeginWrite? - PullRequest
3 голосов
/ 20 февраля 2012

В моем классе Sender есть два метода:

public void SendMessage(OutgoingMessage msg)
{
    try
    {
        stream.BeginWrite(msg.TcpData, 0, 16, messageSentCallback, msg);
    }
    catch
    {
        // ...
    }
}

private void messageSentCallback(IAsyncResult result)
{
    stream.EndWrite(result);

    if (result.IsCompleted)
        onDataSent(result.AsyncState as OutgoingMessage);
}

Другие части программы могут вызывать (если они имеют доступ к Отправителю) метод SendMessage(). Поскольку программа работает в многопоточной среде, несколько потоков имеют доступ к объекту Sender.

У меня 2 вопроса:

Q1) Сможет ли выполнение двух одновременных вызовов метода SendMessage испортить связь TCP (путем заполнения исходящего буфера TCP смешанными данными)?

Q2) Решит ли проблема с включением вызова stream.BeginWrite() в lock { }?

Насколько я понимаю, вызов BeginWrite просто сохраняет данные в исходящем буфере TCP. Это правильно?

Ответы [ 3 ]

3 голосов
/ 20 февраля 2012

Да, для предотвращения проблем необходима блокировка.Однако я бы переключился на другой подход, как для решения проблем параллелизма, так и для упрощения взаимодействия потоков.

У вас может быть общая очередь, в которую несколько потоков помещают запросы, которые необходимо записать в поток.Затем один поток читает запросы из очереди и выполняет операции записи.Теперь гораздо проще понять, что происходит, и вам не нужно беспокоиться о синхронизации записей.Вы можете использовать одну из параллельных коллекций, таких как ConcurrentQueue.

2 голосов
/ 20 февраля 2012

MSDN говорит

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

Это означает, что если у вас есть несколько потоков, отправляющих данные, вы должны использовать lock, чтобы убедиться, что только один поток вызывает BeginWrite одновременно, чтобы отправлять данные без каких-либо помех

1 голос
/ 20 февраля 2012

Если вы хотите минимизировать блокировку и поддерживать высокий параллелизм с несколькими потоками записи, я бы рекомендовал использовать Socket.SendAsync, который принимает SocketAsyncEventArgs.

Вы можете предварительно выделить несколько SocketAsyncEventArgs (со связанным с ним буферным пространством), которые используются как средства записи, и в этом случае вместо блокировки у вас будет SemaphoreSlim, который позволит «одновременных» записей, толкающих синхронизацию вниз по стеку протоколов.

  • Здесь - пример галереи кодов, который может помочь вам начать работу (также демонстрирует объединение для ваших буферов.)
  • Здесь - статья о проекте кода, которая также демонстрирует его использование.

Удачи!

...