[英]C# Threading and using AutoResetEvent
我在類庫中有以下代碼。 我等待回撥到我的主應用程序。 我正在進行DownloadStringAsync調用,因此完成后必須等待幾秒鍾才能獲得回調。 我要等待其中的3個調用,因此在主應用程序中,我正在使用AutoResetEvent等待所有調用完成。 因此,我將阻止直到在回調函數中設置它們。
但是,在測試回調之后,不會調用該回調。 我在想,當代碼被AutoResetEvent阻止時,其阻止DownloadStringAsync。 當我注釋掉此代碼時,一切正常。
因此,我認為只要我打電話給:objNoGateway.NoGatewayStatus(sipUsername,statusDisplay1.PhoneNumber); 當代碼到達此處時:handle.WaitOne(); 它將阻止類庫中的代碼。
非常感謝您的任何建議。
在我的類庫代碼示例中。
// Event handler that makes a call back in my main application
// Event handler and method that handles the event
public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent;
// The method that raises the event.
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
if (NoGatewayCompletedEvent != null)
{
NoGatewayCompletedEvent(this, e);
}
}
// Start the Async call to find if NoGateway is true or false
public void NoGatewayStatus(string sipUsername, string phoneNumber)
{
string strURL = string.Format("http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber);
if (!wc.IsBusy)
{
try
{
string errorMsg = string.Empty;
wc.DownloadStringAsync(new Uri(strURL));
}
catch (WebException ex)
{
Console.WriteLine("IsNoGateway: " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("IsNoGateway: " + ex.Message);
}
}
else
{
Console.WriteLine("WebClient: IsNoGateWay(): Busy please try again");
}
}
void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
if (e.Result == "No gateway")
{
OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.VALIDATION_FAILED));
Console.WriteLine("NoGatway() DownloadedCompleted: " + e.Result);
}
else
{
OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.OK));
Console.WriteLine("NoGateway() DownloadCompleted: " + e.Result);
}
}
else
{
this.OnNoGatewayCompleted(this, new NoGatewayEventArgs(validateResponse_e.SERVER_FAILED));
Console.WriteLine("No Gateway: DownloadCompleted() Error: " + e.Error.Message);
}
}
在我的主應用程序中,我注冊了此回調。 並等待結果。 然后設置AutoResetEvent。
ManualResetEvent[] waitValidateCallResponse = new ManualResetEvent[]
{ new ManualResetEvent(false), new ManualResetEvent(false), new ManualResetEvent(false) };
// Event handler for NoGateway event
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
waitValidateCallResponse[0].Set();
}
我打電話和阻止時的部分。
NoGateway objNoGateway = new NoGateway()
objNoGateway.NoGatewayCompletedEvent += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber);
// Block here - Wait for all reponses to finish before moving on
waitEvent.WaitOne(5000, true);
Console.WriteLine("All thread finished");
========================編輯並添加了其他兩個回調,以免混淆我只有一個=======的問題===============
private void OnCalledNumberBlockedCompleted(object sender, CalledNumberBlockedEventArgs e)
{
Console.WriteLine("OnCalledNumberBlockedCompleted: " + e.CalledNumberBlocked);
waitValidateCallResponse[1].Set();
}
private void OnValidTelephoneNumberCompleted(object sender, ValidTelephoneNumberEventArgs e)
{
Console.WriteLine("OnValidTelephoneNumberCompleted: " + e.validTelephoneNumber);
waitValidateCallResponse[2].Set();
}
簡單嗎:您總是在索引0上調用Set?
private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
waitValidateCallResponse[0].Set();
}
嘗試以下方法:
public void NoGatewayStatus (string sipUsername, string phoneNumber) {
string strURL = string.Format( "http://xxxxxxxxxxxxxxx={0}&CalledNumber={1}", sipUsername, phoneNumber );
ManualResetEvent wait1 = new ManualResetEvent( false );
WebClient wc = new WebClient();
Thread thr = new Thread( DownloadSomeStuff );
thr.Start( new DlArguments( strURL, wait1 ) );
// do the other three
if ( !wait1.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadSomeStuff timed out" );
return;
}
if ( !wait2.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadOtherStuff timed out" );
return;
}
if ( !wait3.WaitOne( 10000 ) ) {
Console.WriteLine( "DownloadMoreStuff timed out" );
return;
}
}
public void DownloadSomeStuff (object p_args) {
DlArguments args = (DlArguments) p_args;
try {
WebClient wc = new WebClient();
wc.DownloadString( args.Url );
args.WaitHandle.Set();
} catch ( Exception ) {
// boring stuff
}
}
private class DlArguments
{
public DlArguments (string url, ManualResetEvent wait_handle) {
this.Url = url;
this.WaitHandle = wait_handle;
}
public string Url { get; set; }
public ManualResetEvent WaitHandle { get; set; }
}
這樣做嗎?
經過大量修改,我想我可能會理解這個問題。 Windows Forms應用程序具有一個主線程; 該線程用於處理消息。 因此,當您的主線程阻塞時,您的應用程序將無法接收事件。 然后使用WaitOne來阻止主線程。
我將WaitOne()檢查移至單獨的計時器線程。
或者,您可以等待有限的時間,並指示應用程序在以下時間之間處理消息:
foreach (WaitHandle handle in waitValidateCallResponse)
{
while (!handle.WaitOne(300))
Application.ProcessMessages();
Console.WriteLine("events.WaitOne(): " + handle.ToString());
}
不過,后一種方法不是您應該在庫中執行的操作。 我認為這是一種反模式。
代碼段特有的
// Event handler that makes a call back in my main application
// Event handler and method that handles the event
public EventHandler<NoGatewayEventArgs> NoGatewayCompletedEvent;
// The method that raises the event.
public void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
if (NoGatewayCompletedEvent != null)
{
NoGatewayCompletedEvent(this, e);
}
}
但是,在最后一個代碼段中,您可以按如下方式為該事件附加一個事件處理程序。.OnNoGatewayCompleted似乎是引發該事件的輔助方法。(不應公開),但是在這里,似乎事件處理程序可以引發該事件。事件再次發生。 除非您有兩個名為OnNoGatewayCompleted的方法(我希望不是)
objNoGateway.NoGatewayCompletedEvent
+= new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);
如果您正在尋找在事件處理程序中發出信號的waitHandles,則不應將方法OnCalledNumberBlockedCompleted掛接到事件上。
PS:正如Marc所指出的..使用WaitHandle.WaitAll (for循環要求異步操作按順序完成,而事實並非如此)
使用WaitHandle.WaitAny(handleArray); 等待handle數組中的所有handle而不是handle.WaitOne(); 循環
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.