guitar80
guitar80

Reputation: 726

Mutex Across Threads?

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

Answers (2)

brainless coder
brainless coder

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:

  1. Task.Run runs asynchronously in a threadpool, which keeps your main thread free all the time.
  2. lock(_lock) ensures only one thread is writing to the stream at any single moment, (threads are spawned by the threadpool from Task.Run)
  3. You don't need a separate writecallback, you could use inline lambda callback methods. Makes life much easier.

Let me know if this solves your problem.

Upvotes: 2

nhabuiduc
nhabuiduc

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

Related Questions