I have an application which uses SslStream
to send and receive data with its own fixed-length framing. The stream is created by wrapping the NetworkStream
returned from TcpClient.GetStream()
like so:
var client = new TcpClient();
client.Connect(host, port);
var sslStream = new SslStream(client.GetStream(), false, callback, null);
sslStream.AuthenticateAsClient(hostname);
Because the protocol is fully asynchronous (framed "messages" arrive at arbitrary times and the client is allowed to send them at arbitrary times), I would normally spawn a thread responsible for blocking on NetworkStream.Read()
and otherwise ensure that there is only one thread calling NetworkStream.Write(...)
at any one time.
The Remarks section for NetworkStream
says:
Read and write operations can be performed simultaneously on an instance of the NetworkStream class without the need for synchronization. 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.
However, the MSDN documentation "Thread Safety" section for SslStream
says:
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
Because SslStream
and NetworkStream
aren't in the same class hierarchy, I have assumed (perhaps incorrectly) that the remarks for NetworkStream
don't apply to SslStream
.
Is the best approach for thread safety to simply wrap SslStream.BeginRead
/ SslStream.EndRead
and SslStream.BeginWrite
/ SslStream.EndWrite
with something like this?
internal sealed class StateObject
{
private readonly ManualResetEvent _done = new ManualResetEvent(false);
public int BytesRead { get; set; }
public ManualResetEvent Done { get { return _done; } }
}
internal sealed class SafeSslStream
{
private readonly object _streamLock = new object();
private readonly SslStream _stream;
public SafeSslStream(SslStream stream)
{
_stream = stream;
}
public int Read(byte[] buffer, int offset, int count)
{
var state = new StateObject();
lock (_streamLock)
{
_stream.BeginRead(buffer, offset, count, ReadCallback, state);
}
state.Done.WaitOne();
return state.BytesRead;
}
public void Write(byte[] buffer, int offset, int count)
{
var state = new StateObject();
lock (_streamLock)
{
_stream.BeginWrite(buffer, offset, count, WriteCallback, state);
}
state.Done.WaitOne();
}
private void ReadCallback(IAsyncResult ar)
{
var state = (StateObject)ar.AsyncState;
lock (_streamLock)
{
state.BytesRead = _stream.EndRead(ar);
}
state.Done.Set();
}
private void WriteCallback(IAsyncResult ar)
{
var state = (StateObject)ar.AsyncState;
lock (_streamLock)
{
_stream.EndWrite(ar);
}
state.Done.Set();
}
}
Net acts as a thread safe FIFO based generic queue. The following is the list of the important methods in the ConcurrentQueue<T> class. TryPeek(out T) - this method is used to retrieve the next element from the queue but it doesn't remove the element from the queue.
A piece of code or data structure is thread safe, when the outcome of the code and underlying resources do not create undesirable results (inconsistent data, exception etc.), because of multiple threads interacting with the code concurrently. That simply means: All threads behave properly.
Provides a stream used for client-server communication that uses the Secure Socket Layer (SSL) security protocol to authenticate the server and optionally the client.
So friends this just an example to make you understand why it is necessary to make thread as Thread Safe in Csharp. In order to make a thread as thread safe there are some thread synchronization techniques like Monitor/Lock, Mutex, Semaphore and SemaphoreSlim using these techniques we can achieve Thread Safety.
The phrase you pulled from the MSDN docs is a catch-all that is placed in the documentation of most classes. If a member's documentation explicitly states thread safety (as NetworkStream
does) then you can rely on it.
However, what they are stating is that you can perform one read and one write at the same time, not two reads or two writes. As such, you will need to synchronise or queue your reads and writes separately. Your code looks sufficient to do this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With