Mutex over streams?
So I am getting an exception from the code below. I put the exception data with it, but I believe it has something to do with another thread releasing the lock and then the one that triggers the lock. I want to do this to potentially allow my main thread to continue while the write queue is in progress.
First of all, I want to know if this can be done? Second, should it be done or is it a bad plan? looked at ManualResetEvent, Monitor and Mutex, all of which seem to do this. Note that this is for a networked server and this is my first time writing multi-threaded, potentially high traffic.
Exception: Thrown the first time the send (and its callback) is called.
System.ApplicationException on mutex.ReleaseMutex (). "The object synchronization method was called from an unsynchronized block of code."
public void SendAsync(byte[] packet)
{
mutex.WaitOne();
client.GetStream().BeginWrite(packet, 0, packet.Length, WriteCallback, null);
}
private void WriteCallback(IAsyncResult ar)
{
client.GetStream().EndWrite(ar);
mutex.ReleaseMutex();
Console.WriteLine("Sent Data to " + RemoteEndPoint);
}
Considering this -
I want to do this to potentially allow my main thread to continue while the write queue is in progress.
First of all, I want to know if this can be done?
I don't think you need it for that mutex
. Are you looking for something like this -
static object _lock = new object(); //somewhere based on your context
public void SendAsync(byte[] packet)
{
Task.Run(() =>
{
..... other codes
lock (_lock)
{
client.GetStream().BeginWrite(packet, 0, packet.Length,
ar => // the write callback (lambda)
{
client.GetStream().EndWrite(ar);
Console.WriteLine("Sent Data to " + RemoteEndPoint);
}, null);
}
});
}
Explanation:
-
Task.Run
runs asynchronously on a thread pool which keeps your main thread free all the time. -
lock(_lock)
ensures that only one stream is written to the stream at any given time (streams are created usingthreadpool
fromTask.Run
) - You don't need a separate one
writecallback
, you can use inline methodslambda callback
. Makes life so much easier.
Let me know if this solves your problem.
Assuming you are using the Mutex class, as per Microsoft
The Mutex class provides thread identification, so a mutex can only be released by the thread that acquired it. In contrast, the Semaphore class does not provide thread identity. A mutex can also be transferred across application domain boundaries.
I think your callback method is being called from another thread, it throws an exception.
As suggested by Microsoft, you can use Semaphore for this situation.
For example:
static volatile Semaphore sem = new Semaphore(1,1);
static void Main(string[] args)
{
Thread oThread = new Thread(new ThreadStart(fn2));
oThread.Start();
Thread.Sleep(200);
sem.WaitOne();
Console.WriteLine("Main is Doing");
Thread.Sleep(2000);
sem.Release();
}
static void fn2()
{
sem.WaitOne();
Console.WriteLine("Thread is Doing");
Thread.Sleep(2000);
sem.Release();
}