c#异步调用方法

时间:2012-08-19 14:03:04

标签: c# asynchronous

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

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

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

尤其是当我不知道status转为true的时间刻度时。

我该怎么做?

更新:我忘了提到我无法更改unit。对不起。

4 个答案:

答案 0 :(得分:2)

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

  1. 附加到属性更改时发出信号的偶数
  2. 定期检查属性的值
  3. 你不能做第一个,所以你必须做第二个。

答案 1 :(得分: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");
    }
}

此输出

Before
After
Manual blocking, or else app dies
Unit_OnChanged before
Unit_OnChanged after
Unit_OnChanged finished

答案 2 :(得分: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();

答案 3 :(得分:0)

如果可能,请使用System.Threading.AutoResetEvent代替bool

AutoResetEvent status = new AutoResetEvent();

在异步方法中,等待它:

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

然后,要在其他课程中发出信号,请致电Set

status.Set();