3

这个类unit有一个属性bool status,用于标记是否request应该在单元上调用方法。我有我的另一个类,其中有一个方法应该调用request. 为了避免阻塞主线程,我想异步调用该方法。问题是状态更改没有事件,我不想让我的异步调用做一些丑陋的事情,比如:

while(!status){}unit.request(args);

或者

while(!status){Thread.Sleep(100)}unit.request(args);

尤其是当我不知道轮到的时间尺度statustrue

我该怎么做呢?

更新:我忘了说我不能改变unit。对此感到抱歉。

4

4 回答 4

2

您想在属性更改时调用函数(无论是否异步)。你有两个选择:

  1. 附加到属性更改时发出信号的偶数
  2. 定期检查财产的价值

你不能做第一个,所以你必须做第二个。

于 2012-08-19T14:06:47.817 回答
2

这是一个如何使用事件来管理它的示例。

假设这是你的课

public class Unit
{
    private readonly object _syncRoot = new object();
    private bool _status;

    public event EventHandler OnChanged;    

    public bool Status
    {
        get
        {
            lock (_syncRoot)
            {
                return _status;    
            }
        }
        set
        {
            lock (_syncRoot)
            {
                _status = value;
                if (_status && OnChanged != null)
                {
                    OnChanged.Invoke(this, null);        
                }
            }
        }
    }

    public void Process()
    {
        Thread.Sleep(1000);
        Status = true;
    }
}

这是您如何使用它的方法

class Program
{
    static void Main(string[] args)
    {
        var unit = new Unit();
        unit.OnChanged += Unit_OnChanged;
        Console.WriteLine("Before");
        Task.Factory.StartNew(unit.Process);
        Console.WriteLine("After");

        Console.WriteLine("Manual blocking, or else app dies");
        Console.ReadLine();
    }

    static void Unit_OnChanged(object sender, EventArgs e)
    {
        //Do your processing here
        Console.WriteLine("Unit_OnChanged before");
        Task.Factory.StartNew(()=>
        {
            Thread.Sleep(1000);
            Console.WriteLine("Unit_OnChanged finished");
        });
        Console.WriteLine("Unit_OnChanged after");
    }
}

这输出

前
后
手动阻止,否则应用程序死机
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged 完成
于 2012-08-19T14:22:01.407 回答
1

这是经典的轮询问题,在轮询方面确实没有一个优雅的解决方案。但是我们可以使用一些函数式编程来获得一些不是噩梦的东西。

    public static CancellationTokenSource Poll(
        Func<bool> termination,
        Action<CancellationToken> onexit,
        int waitTime = 0,
        int pollInterval = 1000)
    {
        var cts = new CancellationTokenSource();
        var token = cts.Token;
        Action dispose = cts.Cancel;

        var timer = new Timer(_ =>
        {
            if (termination() || token.IsCancellationRequested)
            {
                onexit(token);
                dispose();
            }
        }, null, waitTime, pollInterval);

        dispose = timer.Dispose;
        return cts;
    }

例子:

    var condition = false;

    Poll(() => condition == true, ct => Console.WriteLine("Done!"));

    Console.ReadLine();

    condition = true;

    Console.ReadLine();
于 2012-08-19T14:29:27.350 回答
0

如果可能,使用 aSystem.Threading.AutoResetEvent而不是 a :bool

AutoResetEvent status = new AutoResetEvent();

在您的异步方法中,等待它:

status.WaitOne();
unit.request(args);

然后,要在您的其他班级发出信号,请致电Set

status.Set();
于 2012-08-19T14:22:47.517 回答