禁止对象完成,直到其他线程运行

时间:2019-01-21 14:23:55

标签: c# .net

假设我在类中有一些代码,其中一个方法立即返回结果,但在此之前调用后台任务。

class CalculationPolicy 
{
    private readonly IRequestContext _reqContext;

    public CalculationPolicy(IRequestContext reqContext)
    {
       _reqContext = reqContext;
    }

    public ProcessResult Process(object model) 
    {
        var response = new ProcessResult();

        // some synchronous processing ... 
          ............................

        // notifications go into other thread
        Task.Run(() => NotifyCallback(model));

        return response;
    }

    private void NotifyCallback(object model)
    {
       // some notification logic
       // that uses a field [_reqContext]
       string email = _reqContext.GetEmailFromClaims();
    }
}

我想知道垃圾收集器是否知道我的类的实例不应该在其他线程上以该对象的状态保持垃圾收集器不变的方式完成后才完成,

2 个答案:

答案 0 :(得分:4)

当没有更多引用指向该对象时,将收集该对象。安排任务时:

Task.Run(() => NotifyCallback(model));

该委托对您的对象有隐式引用,因此在任务运行之前不会收集该对象。

但是,有点挑剔,您的问题特别是:

  

我想知道垃圾收集器是否知道我的类的实例不应该完成,直到其他线程上的NotifyCallback方法完成

如果您的对象停止引用NotifyCallback,则可能在this的中间收集您的对象。例如:

private void NotifyCallback(object model)
{
   // some notification logic
   // that uses a field [_reqContext]
   string email = _reqContext.GetEmailFromClaims();

   // Do some stuff with email but do not access any field
   // From this point, the object can be collected at any time
   Console.WriteLine(email);   

   Console.WriteLine("Done");
}

从技术上讲,可以在string email = _reqContext.GetEmailFromClaims();之后的任何时间收集您的对象。这应该不成问题,因为您不再使用该类中的任何字段。在极少数情况下会出现问题(通常是在与本机代码进行互操作时),您可以使用GC.KeepAlive来保存引用并人为地延长对象的寿命:

private void NotifyCallback(object model)
{
   // some notification logic
   // that uses a field [_reqContext]
   string email = _reqContext.GetEmailFromClaims();

   // Do some stuff with email but do not access any field
   Console.WriteLine(email);   

   Console.WriteLine("Done");

   GC.KeepAlive(this); // The GC won't collect the object before this line
}

但是实际上在大多数情况下你应该没事。

答案 1 :(得分:1)

由于() => NotifyCallback(model)是实例方法,因此委托人NotifyCallback拥有对您对象的引用。因此,只要由Task.Run创建的Task执行此委托,您的对象就不是垃圾收集的候选对象。