C# 在使用信号量LIM时等待触发事件

C# 在使用信号量LIM时等待触发事件,c#,semaphore,C#,Semaphore,我可以使用信号量lim来等待偶数触发,如下所示: public class MyClass { private SemaphoreSlim _signal; private ObjectThatHasEvent _object; public MyClass() { _signal = new SemaphoreSlim(0, 1); _object = new ObjectThatHasEvent(); _obj

我可以使用信号量lim来等待偶数触发,如下所示:

public class MyClass
{
    private SemaphoreSlim _signal;
    private ObjectThatHasEvent _object;

    public MyClass()
    {
        _signal = new SemaphoreSlim(0, 1);
        _object = new ObjectThatHasEvent();
        _object.OnEventFired += _object_OneEventFired;
    }

    public asnyc void Run()
    {
        _object.DoStuffAndFireEventAfterwards();
        _signal.WaitAsync();
    }

    private void _object_OnEventFired(object sender, EventArgs e)
    {
        _signal.Release();
    }
}
但是,如果我需要先等待来自_对象的事件完成,然后再等待另一个事件,然后再调用_signal.Release,该怎么办?像这样:

public class MyClass
{
    private SemaphoreSlim _signal;
    private ObjectThatHasEvent _object;

    public MyClass()
    {
        _signal = new SemaphoreSlim(0, 1);
        _object = new ObjectThatHasEvent();
        _object.OnConnected += _object_OnConnected;
        _object.OnWorkFinished += _object_OnWorkFinished;
        _object.OnDisconnected += _object_OnDisconnected;            
    }

    public async Task Run()
    {
        _object.Connect();
        await _signal.WaitAsync();
    }

    private void _object_OnConnected(object sender, EventArgs e)
    {
        _object.DoWork();
        //How to wait for work finished here?
        _object.Disconnect();
    }

    private void _object_OnWorkFinished(object sender, EventArgs e)
    {
        //Only disconnect after this has finished...
    }

    private void _object_OnDisconnected(object sender, EventArgs e)
    {
        _signal.Release();
    }
}

根据我的评论,你喜欢这项工作吗

public class MyClass
{
    private SemaphoreSlim _signal;
    private ObjectThatHasEvent _object;

    public MyClass()
    {
        _signal = new SemaphoreSlim(2, 2);
        _object = new ObjectThatHasEvent();
        _object.OnConnected += _object_OnConnected;
        _object.OnWorkFinished += _object_OnWorkFinished;
        _object.OnDisconnected += _object_OnDisconnected;            
    }

    public async Task Run()
    {
        if (_signal.CurrentCount == 2) // Make sure no other connections exist (still 2 threads available)
        {
            await _signal.WaitAsync();
            _object.Connect();
        }
    }

    private void _object_OnConnected(object sender, EventArgs e)
    {
        if (_signal.CurrentCount == 1) //Only do work if we've connected
        {
            await _signal.WaitAsync();
            _object.DoWork();
            _object.Disconnect();
        }
    }

    private void _object_OnWorkFinished(object sender, EventArgs e)
    {
        _signal.Release();
    }

    private void _object_OnDisconnected(object sender, EventArgs e)
    {
        _signal.Release();
    }
}
使用信号量lim作为信号是可能的,但是需要使事件异步友好,即点击。一旦有了异步友好的方法,就可以更自然地组合它们

我更喜欢将TAP包装器作为扩展方法编写,例如:

public static class ObjectThatHasEventExtensions
{
  public static Task ConnectAsync(this ObjectThatHasEvent self)
  {
    // TODO: this wrapper does not handle connection errors.
    var tcs = new TaskCompletionSource<object>();
    EventHandler handler = null;
    handler = (sender, args) =>
    {
      self.OnConnected -= handler;
      tcs.TrySetResult(null);
    };
    self.OnConnected += handler;
    self.Connect();
    return tcs.Task;
  }

  public static Task DoWorkAsync(this ObjectThatHasEvent self)
  {
    // TODO: this wrapper does not handle work errors.
    var tcs = new TaskCompletionSource<object>();
    EventHandler handler = null;
    handler = (sender, args) =>
    {
      self.OnWorkFinished -= handler;
      tcs.TrySetResult(null);
    };
    self.OnWorkFinished += handler;
    self.DoWork();
    return tcs.Task;
  }

  // (same pattern for DisconnectAsync)
}

你能创建另一个信号量吗?或者允许信号灯上有两个线程而不是一个线程,并使用CurrentCount确保信号灯在正确的位置等待?因此,在运行中,确保等待前_signal.CurrentCount==0,在_object_OnConnectedobject sender中,EventArgs e检查_signal.CurrentCount==1,然后再次等待,然后在_object_OnWorkFinishedobject sender、EventArgs e和_objectondisconnectedobject sender中释放,EventArgs eFYI,事件的名称不以On开头。例如,按钮将有一个单击事件,而不是OnClick事件。当您看到OnClick方法时,它们通常是一个受保护的void方法,类用于引发Click事件。这似乎不起作用。线程永远不会超过第二个等待句柄,并且永远不会调用_object_OnWorkFinished。请参阅更新,我认为您需要将_signal.WaitAsync移到dowork上方。等待之后,您需要执行受信号量保护的工作。
public class MyClass
{
  private ObjectThatHasEvent _object;

  public MyClass()
  {
    _object = new ObjectThatHasEvent();
  }

  public async Task Run()
  {
    await _object.ConnectAsync();
    await _object.DoWorkAsync();
    await _object.DisconnectAsync();
  }
}