简体   繁体   English

C#线程化和使用AutoResetEvent

[英]C# Threading and using AutoResetEvent

I have the following code in a class library. 我在类库中有以下代码。 And I wait for a call back into my main application. 我等待回拨到我的主应用程序。 I am making a DownloadStringAsync call so I have to wait a few seconds to get the callback after it has finished. 我正在进行DownloadStringAsync调用,因此完成后必须等待几秒钟才能获得回调。 I have a 3 of these calls to wait for, so in my main application I am using AutoResetEvent to wait all of them to finish. 我要等待其中的3个调用,因此在主应用程序中,我正在使用AutoResetEvent等待所有调用完成。 So I will block until they have been set in the callback function. 因此,我将阻止直到在回调函数中设置它们。

However, after testing the callback don't get called. 但是,在测试回调之后,不会调用该回调。 I am thinking when the code gets blocked by the AutoResetEvent its blocking the DownloadStringAsync. 我在想,当代码被AutoResetEvent阻止时,其阻止DownloadStringAsync。 As when I comment out this code everything works fine. 当我注释掉此代码时,一切正常。

So I think as soon as I make a call to: objNoGateway.NoGatewayStatus(sipUsername, statusDisplay1.PhoneNumber); 因此,我认为只要我打电话给:objNoGateway.NoGatewayStatus(sipUsername,statusDisplay1.PhoneNumber); And when the code reaches here: handle.WaitOne(); 当代码到达此处时:handle.WaitOne(); It will block the code in the class library. 它将阻止类库中的代码。

Many thanks for any advice. 非常感谢您的任何建议。

In my class library code sample. 在我的类库代码示例中。

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

In my main application I register this callback. 在我的主应用程序中,我注册了此回调。 And wait for the for the result. 并等待结果。 Then set the AutoResetEvent. 然后设置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();
    }

The part when I am calling and blocking. 我打电话和阻止时的部分。

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");    

======================== Edit and added the other 2 callbacks as not to confuse the issue of me just having only one ====================== ========================编辑并添加了其他两个回调,以免混淆我只有一个=======的问题===============

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

Is it as simple as: you always call Set on index 0? 简单吗:您总是在索引0上调用Set?

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

Try something along these lines: 尝试以下方法:

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

Does this do it? 这样做吗?

After lots of edits, I think I might understand the problem. 经过大量修改,我想我可能会理解这个问题。 Windows Forms applications have one main thread; Windows Forms应用程序具有一个主线程; this thread is used to process messages. 该线程用于处理消息。 So when your main thread is blocking, your application can't receive events. 因此,当您的主线程阻塞时,您的应用程序将无法接收事件。 And you use WaitOne to keep the main thread blocked. 然后使用WaitOne来阻止主线程。

I'd move the WaitOne() checks to a separate timer thread. 我将WaitOne()检查移至单独的计时器线程。

Or you could wait for a limited time, and instruct the application to process messages in between: 或者,您可以等待有限的时间,并指示应用程序在以下时间之间处理消息:

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

The later approach is not something you should do in a library though. 不过,后一种方法不是您应该在库中执行的操作。 It's something of an anti-pattern I think. 我认为这是一种反模式。

The snippet code is peculiar 代码段特有的

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

However in the 2nd last snippet, you attach an event handler for this event as follows.. OnNoGatewayCompleted seems to be a helper method to raise the event.. (it should not be public) but here it seems you have the event handler raise the event again. 但是,在最后一个代码段中,您可以按如下方式为该事件附加一个事件处理程序。.OnNoGatewayCompleted似乎是引发该事件的辅助方法。(不应公开),但是在这里,似乎事件处理程序可以引发该事件。事件再次发生。 Unless you have 2 methods named OnNoGatewayCompleted (I'm hoping not) 除非您有两个名为OnNoGatewayCompleted的方法(我希望不是)

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

If you're looking for the waitHandles to be signalled in the event handler, shouldn't the methods OnCalledNumberBlockedCompleted be hooked up to the event instead. 如果您正在寻找在事件处理程序中发出信号的waitHandles,则不应将方法OnCalledNumberBlockedCompleted挂接到事件上。

PS: As Marc pointed out.. use WaitHandle.WaitAll ( the for loop demands that the async operations complete in order which may not be the case ) PS:正如Marc所指出的..使用WaitHandle.WaitAll (for循环要求异步操作按顺序完成,而事实并非如此)

Use WaitHandle.WaitAny(handleArray); 使用WaitHandle.WaitAny(handleArray); to wait on all the handles in the handle array instead of handle.WaitOne(); 等待handle数组中的所有handle而不是handle.WaitOne(); in a loop 循环

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM