C#线程化并使用AutoResetEvent

时间:2009-05-11 09:49:46

标签: c# multithreading

我在类库中有以下代码。我等待回到我的主应用程序中。我正在进行一个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");    

========================编辑并添加其他2个回调,以免混淆我只有一个====的问题==================

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

5 个答案:

答案 0 :(得分:1)

它是否如此简单:你总是在索引0上调用Set?

private void OnNoGatewayCompleted(object sender, NoGatewayEventArgs e)
{
    Console.WriteLine("OnNoGatewayComleted: " + e.noGateway);
    waitValidateCallResponse[0].Set();
}

答案 1 :(得分:1)

尝试以下几点:

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

这样做吗?

答案 2 :(得分:0)

经过大量编辑后,我想我可能会理解这个问题。 Windows窗体应用程序有一个主线程;该线程用于处理消息。因此,当您的主线程阻塞时,您的应用程序无法接收事件。并且您使用WaitOne来阻止主线程。

我将WaitOne()检查移动到一个单独的计时器线程。

或者您可以等待一段有限的时间,并指示应用程序处理之间的消息:

foreach (WaitHandle handle in waitValidateCallResponse)
{
    while (!handle.WaitOne(300))
        Application.ProcessMessages();
    Console.WriteLine("events.WaitOne(): " + handle.ToString());
}

后面的方法不是你应该在库中做的事情。我认为这是一种反模式。

答案 3 :(得分:0)

代码段是特殊的

// 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似乎是一个帮助方法来引发事件..(它不应该是公共的)但是这里似乎你有事件处理程序再次引发事件。除非你有2个名为OnNoGatewayCompleted的方法(我希望不是)

objNoGateway.NoGatewayCompletedEvent 
  += new EventHandler<NoGatewayEventArgs>(this.OnNoGatewayCompleted);

如果您正在寻找在事件处理程序中发出信号的waitHandles,则不应将OnCalledNumberBlockedCompleted方法连接到事件上。

PS:正如Marc指出的那样..使用WaitHandle.WaitAll(for循环要求异步操作按顺序完成,可能不是这样)

答案 4 :(得分:-3)

使用WaitHandle.WaitAny(handleArray);等待句柄数组中的所有句柄而不是句柄.WaitOne();在一个循环中