Reputation: 726
So, I am getting an exception with the code below. I have put the exception details with it, but I believe it is caused by the fact that a different thread releases the lock then the one that starts the lock. I want to do this to potentially allow my main thread to continue while the writes queue up and occur.
First and foremost, I want to know if there IS a way this can be done? Secondly, should this be done or is it a bad plan? have looked at ManualResetEvent, Monitor and Mutex all of which seem to do this. Note, this is for a network server and it is my first time writing a multithreaded, potentially high traffic one.
Exception: Thrown the first time a send (and its callback) is called.
System.ApplicationException on mutex.ReleaseMutex(). "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);
}
Upvotes: 5
Views: 2592
Reputation: 6430
Considering this -
I want to do this to potentially allow my main thread to continue while the writes queue up and occur.
First and foremost, I want to know if there IS a way this can be done?
I don't think you need a mutex
for that. 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 in a threadpool, which keeps your main thread free all the time.lock(_lock)
ensures only one thread is writing to the stream at any single moment, (threads are spawned by the threadpool
from Task.Run
)writecallback
, you could use inline lambda callback
methods. Makes life much easier.Let me know if this solves your problem.
Upvotes: 2
Reputation: 1008
Assuming you're using Mutex class, according to Microsoft
The Mutex class enforces thread identity, so a mutex can be released only by the thread that acquired it. By contrast, the Semaphore class does not enforce thread identity. A mutex can also be passed across application domain boundaries.
I think, your callback method is called from another thread, it causes the 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();
}
Upvotes: 4