C# 等待事件-比轮询更好的解决方案?

C# 等待事件-比轮询更好的解决方案?,c#,events,wait,C#,Events,Wait,我正在处理一个现有项目的问题。我们想要读取一个ADC值,通常我们在那里使用一个fire-and-forget概念。我们请求该值,读取该值后引发一个事件。但是现在我必须实现一个函数,它直接返回一个值。我的想法是通过投票来解决这个问题 public class Information { public delegate void NewADCValueArrived(double newValue); private event NewADCValueArrived newAdcV

我正在处理一个现有项目的问题。我们想要读取一个ADC值,通常我们在那里使用一个fire-and-forget概念。我们请求该值,读取该值后引发一个事件。但是现在我必须实现一个函数,它直接返回一个值。我的想法是通过投票来解决这个问题

public class Information
{
    public delegate void NewADCValueArrived(double newValue);

    private event NewADCValueArrived newAdcValue;

    private double getADCValueDirectly()
    {
        double value = -1;

        NewADCValueArrived handler = delegate(double newValue)
        {
                value = newValue;
        };
        newAdcValue += handler;

        askFornewValues(); //Fire and forget

        timeout = 0;
        while(value != -1 && timeout <100)
        {
            timeout++;
            Thread.sleep(1); //Want to avoid this!! because sleeping for 1 ms is very inaccurate
        }

        newAdcValue -= handler;

        if (value != -1)
        {
            return value;
        }
        else
        {
            throw Exception("Timeout");
        }
    }
}
公共类信息
{
公共委托void NewADCValueArrived(双newValue);
私有事件newAdcValue到达newAdcValue;
私有双getadcvaluedirective()
{
双值=-1;
NewADCValueArrived handler=委托(双newValue)
{
值=新值;
};
newAdcValue+=处理程序;
askFornewValues();//触发并忘记
超时=0;

while(value!=-1&&timeout您可以使用
TaskCompletionSource
将事件抽象为
任务
。您可以参考如何操作。您甚至不需要参考答案;问题本身显示了如何操作

一旦你得到了
任务
你就不必再投票了。你可以做各种有趣的事情,比如
等待
继续
,甚至
等待

对于超时,您可以使用带有计时器的call
TaskCompletionSource.setcancelled

关于如何取消订阅活动:(在评论中询问)

公共类MyClass
{
完成公共事件行动;
}
公共静态任务FromEvent(MyClass obj)
{
TaskCompletionSource tcs=新的TaskCompletionSource();
动作完成=空;
完成=()=>
{
tcs.SetResult(空);
obj.OnCompletion-=完成;
};
obj.OnCompletion+=完成;
返回tcs.Task;
}

您可以使用
TaskCompletionSource
将事件抽象为
任务
。您可以参考如何操作。您甚至不需要参考答案;问题本身显示了如何操作

一旦你得到了
任务
你就不必再投票了。你可以做各种有趣的事情,比如
等待
继续
,甚至
等待

对于超时,您可以使用带有计时器的call
TaskCompletionSource.setcancelled

关于如何取消订阅活动:(在评论中询问)

公共类MyClass
{
完成公共事件行动;
}
公共静态任务FromEvent(MyClass obj)
{
TaskCompletionSource tcs=新的TaskCompletionSource();
动作完成=空;
完成=()=>
{
tcs.SetResult(空);
obj.OnCompletion-=完成;
};
obj.OnCompletion+=完成;
返回tcs.Task;
}

如果您有选择,我可能会选择基于任务的解决方案

否则,您可以设置一个AutoResetEvent并等待事件处理程序触发它

private double getADCValueDirectly()
{
    double value = -1;
    AutoResetEvent eventCompleted = new AutoResetEvent(false);
    NewADCValueArrived handler = delegate(double newValue)
    {
        value = newValue;
        // signal the waithandle
        eventCompleted.Set();
    };
    newAdcValue += handler;

    askFornewValues(); //Fire and forget
    eventCompleted.WaitOne(); // optionally enter a timeout here

    newAdcValue -= handler;

    if (value != -1)
    {
        return value;
    }
    else
    {
        throw Exception("Timeout");
    }
}

上有一篇关于C#线程处理的优秀教程,如果你有选择的话,我可能会选择基于任务的解决方案

否则,您可以设置一个AutoResetEvent并等待事件处理程序触发它

private double getADCValueDirectly()
{
    double value = -1;
    AutoResetEvent eventCompleted = new AutoResetEvent(false);
    NewADCValueArrived handler = delegate(double newValue)
    {
        value = newValue;
        // signal the waithandle
        eventCompleted.Set();
    };
    newAdcValue += handler;

    askFornewValues(); //Fire and forget
    eventCompleted.WaitOne(); // optionally enter a timeout here

    newAdcValue -= handler;

    if (value != -1)
    {
        return value;
    }
    else
    {
        throw Exception("Timeout");
    }
}

上有一个关于C#线程处理的优秀教程,如果它真的是实时的,并且您负担不起让调度程序采取行动,那么您可以进行忙碌的等待:

timeout=0;

而(value!=-1&&timeout如果它真的是实时的,并且您负担不起让调度器采取行动,那么您可以进行繁忙的等待:

timeout=0;

而(value!=-1&&timeout
100000*100
繁忙等待的迭代次数?您可能只是为了等待而计划烧掉cpu?在1Ghz cpu上,这将需要100k*100=10M周期==100ms(实际需要的数字会有所不同…)
100000*100
busy wait的迭代次数?您可能只是为了等待而计划烧掉cpu?在1Ghz的cpu上,这将需要100k*100=10M周期==100ms(实际需要的数字会有所不同…),感谢您的解决方案。链接页面上有一个问题:每次我调用FromEvent()函数在事件中添加了一个新函数。我是否必须在事后删除此函数,还是垃圾收集器为我执行此操作。在我的情况下,此函数可以经常调用。感谢您的解决方案。链接页面上有一个问题:每次我调用FromEvent()时函数在事件中添加了一个新函数。我是否必须在事后删除此函数,或者垃圾收集器是否为我执行此操作。在我的情况下,可以经常调用此函数。
    timeout = 0;
    while(value != -1 && timeout <100000)
    {
        timeout++;
        for(int j= 0; j < 100; j++); // keep CPU busy
    }