【问题标题】:AutoResetEvent doesn't work by some reasonAutoResetEvent 由于某种原因不起作用
【发布时间】:2012-11-02 07:48:49
【问题描述】:

upd 我发现 AutoResetEvent 按预期工作。看来我在CalculateAndNotify 的某个地方有异常。所以这个问题不再是关于 AutoResetEvent 了。但是,如果您能提出如何更好地在 HFT 软件中计算索引的建议,欢迎使用 cmets。

================================================ ================================ 我在我的班级的完整列表下方添加。有两种重要的方法。每次调用 InstrumentUpdated 时,Calculate 都会重新计算索引值。

class CompositeIndex : CustomIndex
{
    //private Tuple<Instrument, double>[] _instrumentsWithWeight;
    //private int[] _instrumentIds;
    //private double[] _ammounts;
    //private double[] _cachedProduct; // one thread writes here and another thread reads. so need to use "Volatile"
    //private volatile bool _initialized;

    //AutoResetEvent are = new AutoResetEvent(false);

    //public CompositeIndex(string indexId, Tuple<Instrument, double>[] instrumentsWithWeight)
    //    : base(indexId, GetInstruments(instrumentsWithWeight))
    //{
    //    _instrumentsWithWeight = instrumentsWithWeight;
    //    _instrumentIds = new int[_instrumentsWithWeight.Count()];
    //    _ammounts = new double[Commons.Constants.MAX_INSTRUMENTS_NUMBER_IN_SYSTEM];
    //    _cachedProduct = new double[Commons.Constants.MAX_INSTRUMENTS_NUMBER_IN_SYSTEM];

        Task.Factory.StartNew(() =>
                {
                    while(true)
                    {
                        if (_initialized)
                        {
                            break;
                        }
                        Thread.Sleep(1000);
                    }
                    while (true)
                    {
                        are.WaitOne();             // hangs here!
                        CalculateAndNotify();
                    }
                }
            , TaskCreationOptions.LongRunning);
    }

    //private static List<Instrument> GetInstruments(Tuple<Instrument, double>[] instrumentsWithWeight)
    //{
    //    List<Instrument> result = new List<Instrument>();
    //    for (int i = 0; i < instrumentsWithWeight.Count(); i++)
    //    {
    //        result.Add(instrumentsWithWeight[i].Item1);
    //    }
    //    return result;
    //}

    //protected override void Calculate()
    //{
    //    double result = 0;
    //    for (int i = 0; i < _instrumentIds.Count(); i++)
    //    {
    //        int instrumentId = _instrumentIds[i];
    //        // we assign 0 weself so this comparision is OK
    //        double cachedProduct = Volatile.Read(ref _cachedProduct[instrumentId]);
    //        if (cachedProduct == 0)
    //        {
    //            Value = null;
    //            return;
    //        }
    //        result += cachedProduct;
    //    }
    //    Value = result;
    //}

    //private object _initializeLock = new object();

    //private bool Initialize()
    //{
    //    lock (_initializeLock)
    //    {
    //        if (_initialized)
    //        {
    //            return true;
    //        }
    //        for (int i = 0; i < _instrumentsWithWeight.Count(); i++)
    //        {
    //            Instrument instrument = _instrumentsWithWeight[i].Item1;
    //            double weight = _instrumentsWithWeight[i].Item2;
    //            _instrumentIds[i] = instrument.Id;
    //            _ammounts[instrument.Id] = weight;
    //        }
    //        _initialized = true;
    //        return true;
    //    }
    //}

    public override void InstrumentUpdated(Instrument instrument)
    {
        //if (!_initialized)
        //{
        //    if (!Initialize())
        //    {
        //        return;
        //    }
        //}
        //int instrumentId = instrument.Id;
        //bool useSecurityInsteadOfOrderBook = instrument.GateId == 1;

        //decimal? value;
        //if  (useSecurityInsteadOfOrderBook)
        //{
        //    InstrumentInfo ii = Markets.GetInstrumentInfo(instrument);
        //    value = ii.MedianOrAskOrBid;
        //} else
        //{
        //    Glass glass = Markets.GetGlass(instrument);
        //    value = glass.MedianOrAskOrBid;
        //}


        //if (value == null)
        //{
        //    Volatile.Write(ref _cachedProduct[instrumentId], 0);
        //}
        //else
        //{
        //    Volatile.Write(ref _cachedProduct[instrumentId], ((double)value) * _ammounts[instrumentId]);
        //}
        are.Set();      // called many times!
    }

}

我添加了一些跟踪并注意到: 一个线程挂在are.WaitOne()。尽管另一个线程多次调用are.Set(),但第一个线程没有被释放。 为什么?我的代码有什么问题?

【问题讨论】:

  • 代码太多。尝试通过删除不相关的部分来定位问题。
  • @DmitryDovgopoly 只需看看“Calculate”和“InstrumentUpdated”方法!我将评论不重要的代码。
  • calculatenotify 是做什么的。
  • @CodeIgnoto 我评论了不重要的代码。重要的是 - 当are.Set() 被调用时,我没有在are.WaitOne() 中得到通知
  • @CodeIgnoto CalculateAndNotify 调用 Calculate() 然后通知侦听器。

标签: c# multithreading events autoresetevent


【解决方案1】:
 public override void InstrumentUpdated(Instrument instrument)
 {
    //your code
    // are.Set - do not need

    Task.Factory.StartNew(CalculateAndNotify, TaskCreationOptions.LongRunning);
 }

你应该改变CalculateAndNotify

 protected void CalculateAndNotify()
 {
     if (Monitor.TryEnter(someObject))
     {
         try
         {
             // your code
         }
         finally
         {
             Monitor.Exit(someObject);
         }
     }
 }

这可能会做你想做的事

【讨论】:

  • InstrumentUpdated 方法应尽快返回,而不是阻止调用者。不应添加锁。
  • InstrumentUpdated 不会锁定,因为它只会启动新线程。 CalculateAndNotify 方法应该有锁
  • 每次仪器更新(每秒超过 100 次)都启动一个新线程太贵了
  • 我的意思是它创建新任务,女巫会使用线程池,所以它不会太贵。
  • 我不确定创建如此密集的任务是否是个好主意,但如果可以的话,欢迎提供任何相关链接 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多