upd AutoResetEvent が期待どおりに機能することがわかりました。内部のどこかに例外があるようですCalculateAndNotify
。したがって、この質問は AutoResetEvent に関するものではありません。しかし、HFT ソフトウェアでインデックスをより適切に計算する方法を提案できる場合は、コメントを歓迎します。
================================================== ============================ クラスの完全なリストの下に追加します。2 つの重要な方法があります。が呼び出されるCalculate
たびにインデックス値を再計算しています。InstrumentUpdated
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!
}
}
いくつかのトレースを追加したところ、次のことに気付きました: 1 つのスレッドが でハングしare.WaitOne()
ます。別のスレッドが何度も呼び出しているにもかかわらずare.Set()
、最初のスレッドは解放されません。なんで?コードの何が問題になっていますか?