IT이야기

C#에서 이벤트가 발생할 때까지 차단하는 방법

cyworld 2021. 10. 28. 19:19
반응형

C#에서 이벤트가 발생할 때까지 차단하는 방법


이 질문을 한 후 이벤트가 발생하기를 기다렸다가 이벤트 데이터를 가져와서 그 일부를 반환할 수 있는지 궁금합니다. 다음과 같은 종류:

private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();

제공하는 솔루션이 다른 것에서 값을 가져오는 대신 직접 값을 반환하는지 확인하십시오. 위의 방법이 어떤 식 으로든 사용할 수 있는지 묻습니다. Auto/ManuelResetEvent에 대해 알고 있지만 위에서 했던 것처럼 직접 값을 반환하는지 모르겠습니다.

업데이트:MyEventHandler ( Message필드 가 포함된 ) 이벤트를 선언했습니다 . ReadLine이벤트가 발생하기를 기다리는 다른 스레드에 메서드가 있습니다. 이벤트가 발생하면 WaitForValue 메서드(이벤트 처리 장면의 일부)는 메시지가 포함된 이벤트 인수를 반환합니다. 그런 다음 메시지는 ReadLine에 의해 호출된 모든 항목으로 반환됩니다.

허용 대답그 질문에 내가 물었다 내가 무슨 짓을했지만, 그냥 아주 느낌이 좋지 않습니다. ManuelResetEvent 실행과 프로그램이 데이터를 검색하고 반환하는 사이에 데이터에 무슨 일이 일어날 수 있는 것처럼 느껴집니다.

업데이트: 주요 문제 Auto/ManualResetEvent는 너무 취약하다는 것입니다. 스레드는 이벤트를 기다렸다가 다른 이벤트로 변경하기 전에 다른 사람이 이벤트를 얻을 수 있도록 충분한 시간을 주지 않을 수 있습니다. 잠금이나 다른 것을 사용하는 방법이 있습니까? get 및 set 문을 사용할 수 있습니다.


ManualResetEvent 를 사용할 수 있습니다 . 보조 스레드를 실행하기 전에 이벤트를 재설정한 다음 WaitOne() 메서드를 사용하여 현재 스레드를 차단합니다. 그런 다음 보조 스레드에서 기본 스레드가 계속되도록 하는 ManualResetEvent를 설정할 수 있습니다. 이 같은:

ManualResetEvent oSignalEvent = new ManualResetEvent(false);

void SecondThread(){
    //DoStuff
    oSignalEvent.Set();
}

void Main(){
    //DoStuff
    //Call second thread
    System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
    oSecondThread.Start();

    oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
    oSignalEvent.Reset();
    //Do more stuff
}

현재 메서드가 비동기인 경우 TaskCompletionSource를 사용할 수 있습니다. 이벤트 핸들러와 현재 메서드가 액세스할 수 있는 필드를 만듭니다.

    TaskCompletionSource<bool> tcs = null;

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        tcs = new TaskCompletionSource<bool>();
        await tcs.Task;
        WelcomeTitle.Text = "Finished work";
    }

    private void Button_Click2(object sender, RoutedEventArgs e)
    {
        tcs?.TrySetResult(true);
    }

이 예에서는 WelcomeTitle이라는 텍스트 블록과 두 개의 버튼이 있는 양식을 사용합니다. 첫 번째 버튼을 클릭하면 클릭 이벤트가 시작되지만 대기 줄에서 멈춥니다. 두 번째 버튼을 클릭하면 작업이 완료되고 WelcomeTitle 텍스트가 업데이트됩니다. 시간 초과를 원하면 변경하십시오.

await tcs.Task;

에게

await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
    WelcomeTitle.Text = "Task Completed";
else
    WelcomeTitle.Text = "Task Timed Out";

당신이 기다릴 수 있는 아주 쉬운 종류의 이벤트는 ManualResetEvent, 그리고 더 좋은 것은 ManualResetEventSlim.

그들은 WaitOne()정확히 그것을 수행 하는 방법을 가지고 있습니다 . 영원히 기다리거나 시간 제한을 설정하거나 이벤트 대기를 중단하기로 결정하는 "취소 토큰"을 설정할 수 있습니다(작업을 취소하거나 앱을 종료하라는 메시지가 표시되는 경우).

당신 은 전화 를 해고 Set().

여기 문서가 있습니다.


Microsoft Reactive Extensions를 사용하게 된다면 다음과 같이 잘 작동할 수 있습니다.

public class Foo
{
    public delegate void MyEventHandler(object source, MessageEventArgs args);
    public event MyEventHandler _event;
    public string ReadLine()
    {
        return Observable
            .FromEventPattern<MyEventHandler, MessageEventArgs>(
                h => this._event += h,
                h => this._event -= h)
            .Select(ep => ep.EventArgs.Message)
            .First();
    }
    public void SendLine(string message)
    {
        _event(this, new MessageEventArgs() { Message = message });
    }
}

public class MessageEventArgs : EventArgs
{
    public string Message;
}

I can use it like this:

var foo = new Foo();

ThreadPoolScheduler.Instance
    .Schedule(
        TimeSpan.FromSeconds(5.0),
        () => foo.SendLine("Bar!"));

var resp = foo.ReadLine();

Console.WriteLine(resp);

I needed to call the SendLine message on a different thread to avoid locking, but this code shows that it works as expected.

ReferenceURL : https://stackoverflow.com/questions/12745848/how-to-block-until-an-event-is-fired-in-c-sharp

반응형