Kornelije Petak
Kornelije Petak

Reputation: 9572

What can happen in two concurrent NetworkStream.BeginWrite calls?

I have two methods on my Sender class:

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);
}

Other parts of the program can call (if they have an access to the Sender) the SendMessage() method. Since the program works in multi-threading environment, multiple threads have access to the Sender object.

I have 2 questions:

Q1) Would making two concurrent calls to the SendMessage method be able to mess up the TCP communication (by filling the TCP outgoing buffer with mixed data)?

Q2) Would enclosing the stream.BeginWrite() call into the lock { } solve this problem?

As far as I understand, the call to BeginWrite simply stores the data into the TCP outgoing buffer. Is that right?

Upvotes: 3

Views: 3569

Answers (3)

Anastasiosyal
Anastasiosyal

Reputation: 6626

If you would like to minimize blocking and maintain high concurrency with multiple writer threads I would recommend using the Socket.SendAsync which accepts a SocketAsyncEventArgs.

You could preallocate a number of SocketAsyncEventArgs (with its associated buffer space) that are used as writers, in which case, rather than having a lock you would have a SemaphoreSlim which would allow a number of 'simultaneous' writes pushing the synching lower down the protocol stack.

  • Here is a Code Gallery sample that could get you started (also demonstrates pooling for your buffers.)
  • Here is a codeproject article that also demonstrates its use.

Good luck!

Upvotes: 1

Tudor
Tudor

Reputation: 62469

Yes, a lock is required to avoid problems. However, I would switch to a different approach, both to solve concurrency problems as well as to make the thread interaction more easy to reason about.

You could have a shared queue where several threads put requests that need to be written to the stream. A single thread then reads requests from the queue and makes write operations. Now it's much easier to understand what is going on and you don't have to worry about synchronizing the writes. You could use one of the concurrent collections like ConcurrentQueue.

Upvotes: 3

Haris Hasan
Haris Hasan

Reputation: 30127

MSDN Says

As long as there is one unique thread for the write operations and one unique thread for the read operations, there will be no cross-interference between read and write threads and no synchronization is required.

Which means that if you have more than one threads sending data then you should use lock to make sure only one thread calls BeginWrite at a time in order to send data without any interference

Upvotes: 1

Related Questions