Mutex跨线程?

时间:2015-05-12 03:36:14

标签: c# multithreading callback network-programming mutex

所以,我收到以下代码的异常。我已经把它的异常细节,但我相信它是由一个不同的线程释放锁然后启动锁定的事实引起的。我希望这样做可能允许我的主线程在写入队列结束时继续。

首先,我想知道是否有办法可以做到这一点?其次,如果这样做或者这是一个糟糕的计划?看过ManualResetEvent,Monitor和Mutex所有这些似乎都是这样做的。请注意,这是针对网络服务器的,这是我第一次编写多线程,可能是高流量的服务器。

异常:第一次调用send(及其回调)时抛出。

  

mutex.ReleaseMutex()上的System.ApplicationException。 “从非同步的代码块调用了对象同步方法。”

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

2 个答案:

答案 0 :(得分:3)

假设您正在使用Mutex类,根据Microsoft

  

Mutex类强制执行线程标识,因此互斥锁只能由获取它的线程释放。相比之下,Semaphore类不强制执行线程标识。互斥体也可以跨应用程序域边界传递。

我认为,你的回调方法是从另一个线程调用的,它会导致异常 正如Microsoft建议的那样,您可以在这种情况下使用Semaphore。

例如:

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

答案 1 :(得分:2)

考虑到这一点 -

  

我想这样做可能允许我的主线程在写入队列结束时继续。

     

首先,我想知道是否有办法可以做到这一点?

我认为你不需要mutex。你在寻找这样的东西 -

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

说明:

  1. Task.Run在线程池中异步运行,这样可以保持主线程一直空闲。
  2. lock(_lock)确保在任何一个时刻只有一个线程正在写入流(线程由threadpool Task.Run生成
  3. 您不需要单独的writecallback,您可以使用内联lambda callback方法。让生活更轻松。
  4. 如果这可以解决您的问题,请告诉我。