跨线程互斥?
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);
}
});
}
解释:
Task.Run
在线程池中异步运行,让您的主线程始终保持空闲状态。
lock(_lock)
确保在任何时刻只有一个线程正在写入流,(线程由 Task.Run
中的 threadpool
产生)
- 您不需要单独的
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();
}
所以,下面的代码出现异常。我已经把异常细节放在一起,但我相信这是由于不同的线程释放锁然后启动锁的线程造成的。我想这样做是为了在写入排队并发生时允许我的主线程继续。
首先,我想知道是否有办法做到这一点?其次,应该这样做还是一个糟糕的计划?已经查看了 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);
}
});
}
解释:
Task.Run
在线程池中异步运行,让您的主线程始终保持空闲状态。lock(_lock)
确保在任何时刻只有一个线程正在写入流,(线程由Task.Run
中的threadpool
产生)- 您不需要单独的
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();
}