我有這兩個類:LineWriter和AsyncLineWriter。我的目標是允許調用者在AsyncLineWriter的方法上排隊多個掛起的異步調用,但在封面下永遠不會允許它們並行運行;即他們必須以某種方式排隊等待彼此。而已。這個問題的其餘部分給出了一個完整的例子,所以對於我真正問的問題絕對沒有歧義。如何強制C#異步操作以...同步方式運行?
LineWriter具有大約需要5秒鐘運行單個同步方法(的WriteLine):
public class LineWriter
{
public void WriteLine(string line)
{
Console.WriteLine("1:" + line);
Thread.Sleep(1000);
Console.WriteLine("2:" + line);
Thread.Sleep(1000);
Console.WriteLine("3:" + line);
Thread.Sleep(1000);
Console.WriteLine("4:" + line);
Thread.Sleep(1000);
Console.WriteLine("5:" + line);
Thread.Sleep(1000);
}
}
AsyncLineWriter只是封裝LineWriter並提供一個異步接口(BeginWriteLine和EndWriteLine):
public class AsyncLineWriter
{
public AsyncLineWriter()
{
// Async Stuff
m_LineWriter = new LineWriter();
DoWriteLine = new WriteLineDelegate(m_LineWriter.WriteLine);
// Locking Stuff
m_Lock = new object();
}
#region Async Stuff
private LineWriter m_LineWriter;
private delegate void WriteLineDelegate(string line);
private WriteLineDelegate DoWriteLine;
public IAsyncResult BeginWriteLine(string line, AsyncCallback callback, object state)
{
EnterLock();
return DoWriteLine.BeginInvoke(line, callback, state);
}
public void EndWriteLine(IAsyncResult result)
{
DoWriteLine.EndInvoke(result);
ExitLock();
}
#endregion
#region Locking Stuff
private object m_Lock;
private void EnterLock()
{
Monitor.Enter(m_Lock);
Console.WriteLine("----EnterLock----");
}
private void ExitLock()
{
Console.WriteLine("----ExitLock----");
Monitor.Exit(m_Lock);
}
#endregion
}
正如我在第一段中所說的,我的目標是一次只允許一個掛起的異步操作。我會真的喜歡它,如果我不需要在這裏使用鎖;也就是說,如果BeginWriteLine可以返回一個總是立即返回並保持預期行爲的IAsyncResult句柄,那將會很棒,但我不知道該怎麼做。所以下一個最好的方式來解釋我後來似乎只是使用鎖。
不過,我的「鎖定東西」部分沒有按預期工作。我期望上面的代碼(在異步操作開始之前運行EnterLock,在異步操作結束之後運行ExitLock)只允許在任何給定時間運行一個掛起的異步操作。
如果我運行下面的代碼:
static void Main(string[] args)
{
AsyncLineWriter writer = new AsyncLineWriter();
var aresult = writer.BeginWriteLine("atest", null, null);
var bresult = writer.BeginWriteLine("btest", null, null);
var cresult = writer.BeginWriteLine("ctest", null, null);
writer.EndWriteLine(aresult);
writer.EndWriteLine(bresult);
writer.EndWriteLine(cresult);
Console.WriteLine("----Done----");
Console.ReadLine();
}
我預計看到下面的輸出:
----EnterLock----
1:atest
2:atest
3:atest
4:atest
5:atest
----ExitLock----
----EnterLock----
1:btest
2:btest
3:btest
4:btest
5:btest
----ExitLock----
----EnterLock----
1:ctest
2:ctest
3:ctest
4:ctest
5:ctest
----ExitLock----
----Done----
而是我看到以下,這意味着他們都只是平行運行,好像鎖不起作用:
----EnterLock----
----EnterLock----
----EnterLock----
1:atest
1:btest
1:ctest
2:atest
2:btest
2:ctest
3:atest
3:btest
3:ctest
4:atest
4:btest
4:ctest
5:atest
5:btest
5:ctest
----ExitLock----
----ExitLock----
----ExitLock----
----Done----
我假設鎖被「忽略」,因爲(並糾正我,如果我錯了)我將它們從同一個線程全部鎖定。我的問題是:如何可以我得到了我的預期行爲?而「不要使用異步操作」不是一個可以接受的答案。
有一個更大,更復雜的真實生活用例,使用異步操作,有時不可能有多個真正的並行操作,但我需要至少模擬行爲,即使它意味着排隊操作並一個接一個地運行它們。具體而言,AsyncLineWriter的接口不應該改變,但它的內部行爲需要以線程安全的方式排隊它的任何異步操作。另一個問題是,我無法將鎖添加到LineWriter的WriteLine中,因爲在我的實際情況中,這是一種我無法更改的方法(儘管在此示例中實際上確實會給我預期的輸出)。
設計用於解決類似問題的代碼的鏈接可能足以讓我走上正確的道路。或者也許有一些替代想法。謝謝。
P.S.如果你想知道什麼樣的用例可能會使用這樣的事情:它是一個維護網絡連接的類,一次只能激活一個操作;我爲每個操作使用異步調用。沒有明顯的方法可以通過單一網絡連接實現真正的並行通信線路,因此它們需要以某種方式彼此等待。
我說'預計'我應該說'想要'。 –