【dinghao】在Asp.net中呼叫非同步方法--使用訊號量

iDotNetSpace發表於2008-06-05
 時間耦合:併發和次序(事件在時間中的相對位置,即“塔”必須在“嘀”之前發生)
    有些庫可能只提供了非同步方法,而ASP.net確是同步的,這次就遇到一個問題:頁面顯示出來以後才會執行回撥函式。而我需要的流程是:在回撥函式中執行驗證,然後才能呈現頁面。Mutex,AutoResetEvent提供了通過訊號量來協調執行緒執行步驟的方法。
    XmppClientConnection是agsxmppJabber庫中的類,呼叫Open會立即返回客戶端(ie)呈現該頁面,而不管是否成功,同時會在另一個執行緒會執行登陸,新建帳戶的操作,成功後會觸發回撥事件,這樣一來頁面呈現後才會執行回撥,不符合我們要的邏輯。我們把呼叫Open的執行緒叫做:Jabber執行緒,把執行登陸的執行緒叫做:Jabber執行緒的輔助執行緒。

    我最初的想法是使用Moniter,程式碼:

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量private object objlock=new object();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
public void RegisterJab(string username, string password, string server)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Server 
= server;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Username 
= username;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Password 
= password;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Port 
= 80;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.UseSSL 
= false;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.AutoResolveConnectServer 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.ConnectServer 
= null;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.SocketConnectionType 
= agsXMPP.net.SocketConnectionType.Direct;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.UseStartTLS 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.RegisterAccount 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            Moniter.Enter(objlock);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Open();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            Moniter.Wait(objlock);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Close();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
private void XmppCon_OnRegistered(object sender)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            IsSuccessfull 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            Moniter.Exit(objlock);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }


    在執行Moniter.Exit()時會丟擲異常:SynchronizationLockException,因為Jabber輔助執行緒並不是鎖的擁有者.發現Moniter很像臨界區,並不適處理這種情況合。
    後來,轉到了Mutex,Mutex: 是同步基元,它只向一個執行緒授予對共享資源的獨佔訪問權。如果一個執行緒獲取了互斥體,則要獲取該互斥體的第二個執行緒將被掛起,直到第一個執行緒釋放該互斥體。
    Mutex很合適這個功能的實現,可是還有沒有更簡便的方法呢?那就是AutoResetEvent:允許執行緒通過發訊號互相通訊。通常,此通訊涉及執行緒需要獨佔訪問的資源。最重要的是他提供了執行緒間通訊的方法,這樣可以更靈活的控制執行緒的呼叫步驟,我們用到的就是訊號量。
程式碼:

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量namespace LoginBase
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量    
public class Register
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量    
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        XmppClientConnection _connection;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
static AutoResetEvent myResetEvent;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
public bool IsUsed;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
public Register()
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection 
= new XmppClientConnection();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.SocketConnectionType 
= agsXMPP.net.SocketConnectionType.Direct;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.OnLogin 
+= new ObjectHandler(XmppCon_OnLogin);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.OnRegisterError 
+= new OnXmppErrorHandler(XmppCon_OnRegErr);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.OnRegistered 
+= new ObjectHandler(XmppCon_OnRegistered);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
public bool IsSuccessfull = false;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
public void RegisterJab(string username, string password, string server)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Server 
= server;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Username 
= username;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Password 
= password;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Port 
= 80;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.UseSSL 
= false;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.AutoResolveConnectServer 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.ConnectServer 
= null;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.SocketConnectionType 
= agsXMPP.net.SocketConnectionType.Direct;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.UseStartTLS 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.RegisterAccount 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            myResetEvent 
= new AutoResetEvent(false);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Open();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            myResetEvent.WaitOne(
20 * 1000true);
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            _connection.Close();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
private void XmppCon_OnRegistered(object sender)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            IsSuccessfull 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            myResetEvent.Set();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
private void XmppCon_OnLogin(object sender)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            IsSuccessfull 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            myResetEvent.Set();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
private void XmppCon_OnRegErr(object sender, Element e)
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        
{
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            
//errCode如果是409則已經存在使用者
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
            IsSuccessfull = false;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            Element xn 
= e.SelectSingleElement("error");
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            
if (xn.Attribute("code"== "409")
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量                IsUsed 
= true;
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量            myResetEvent.Set();
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量        }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量    }

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量}

【dinghao】在Asp.net中呼叫非同步方法--使用訊號量
【dinghao】在Asp.net中呼叫非同步方法--使用訊號量

    先設定為非終止狀態,然後進入Jabber執行緒,阻塞Asp執行緒,並且等待,超時時間為20秒。如果觸發了回撥事件,則設定狀態為終止,asp執行緒繼續執行。
    成功完成同步,這樣一來,必須等到Jabber輔助執行緒執行完,Asp執行緒才會繼續下去。
注:RegisterAsyncTask,也可以實現類似功能。好像它和非同步頁有很強的關聯,用它實現這個類就沒有了通用性。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-332342/,如需轉載,請註明出處,否則將追究法律責任。

相關文章