跨线程互斥?

Mutex Across Threads?

所以,下面的代码出现异常。我已经把异常细节放在一起,但我相信这是由于不同的线程释放锁然后启动锁的线程造成的。我想这样做是为了在写入排队并发生时允许我的主线程继续。

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

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

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

考虑到这一点 -

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?

我认为您不需要 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) 确保在任何时刻只有一个线程正在写入流,(线程由 Task.Run 中的 threadpool 产生)
  3. 您不需要单独的 writecallback,您可以使用内联 lambda callback 方法。让生活更轻松。

如果这能解决您的问题,请告诉我。

假设您正在使用 Mutex class,根据 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.

我想,你的回调方法是从另一个线程调用的,它导致了异常。
根据 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();
    }