[英]Copying a struct results in empty struct
I have a weird behaviour in a multithreaded environment: A value in a struct is empty at runtime but contains something when in break mode.我在多线程环境中有一个奇怪的行为:结构中的值在运行时为空,但在中断模式下包含一些东西。
Given the following function:给定以下 function:
public static double Convert_CurrencyValue(SlimOrderbook orderBook,
double amountToConvert, bool backward = false)
{
OrderBookPrice price;
double result;
if (!backward)
{
price = orderBook.Bids[0];
result = amountToConvert * price.Price;
}
else
{
price = orderBook.Asks[0];
result = amountToConvert / price.Price;
}
if (double.IsInfinity(result) || double.IsNaN(result))
{
{ /* break marker here "/ }
}
return result;
}
For some reason, sometimes (not always) result will come out infinity.出于某种原因,有时(并非总是)结果会无穷大。
I added the if statement and a break marker to see what's happening exactly.我添加了 if 语句和一个中断标记来查看到底发生了什么。
In case of the issue, OrderbookPrice price
equates to the following:如果出现问题, OrderbookPrice price
等于以下内容:
double Price: 0;
double ImpliedProfit: 0;
double Volume: 0;
At the same time, when in the break marker, SlimOrderbook orderBook.Asks[0]
equates to something like follows:同时,在中断标记中, SlimOrderbook orderBook.Asks[0]
等同于如下内容:
double Price: 42.5232;
double ImpliedProfit: -0.01;
double Volume: 0.43;
This is a screenshot of my debug view:这是我的调试视图的屏幕截图:
The two mainly involved Data structures are class Orderbook
and struct SlimOrderbook
主要涉及的两个数据结构分别是class Orderbook
和struct SlimOrderbook
SlimOrderbook: SlimOrderbook:
public struct SlimOrderbook
{
public SlimOrderbook(OrderBookPrice[] asks, double spot, OrderBookPrice[] bids)
{
Asks = asks;
SpotPrice = spot;
Bids = bids;
}
public OrderBookPrice[] Asks { get; private set; }
public double SpotPrice { get; private set; }
public OrderBookPrice[] Bids { get; private set; }
}
public struct OrderBookPrice
{
public double Price;
public double Volume;
public double ImpliedProfit;
}
SlimOrderbook is beeing generated from within OrderBook
as a one off working copy which can locally be worked with: SlimOrderbook 是从OrderBook
中生成的,作为可以在本地使用的一次性工作副本:
public SlimOrderbook GetOrderBook(Currency baseCurrency, Currency quoteCurrency)
{
if (baseCurrency.Equals(CurrencyPair.BaseCurrency) && quoteCurrency.Equals(CurrencyPair.QuoteCurrency))
{
return new SlimOrderbook(asks: (OrderBookPrice[])Asks.Clone(), spot: SpotPrice, bids: (OrderBookPrice[])Bids.Clone());
}
else if (baseCurrency.Equals(CurrencyPair.QuoteCurrency) && quoteCurrency.Equals(CurrencyPair.BaseCurrency))
{
return new SlimOrderbook(asks: (OrderBookPrice[])InvertedAsks.Clone(), spot: InvertedSpotPrice, bids: (OrderBookPrice[])InvertedBids.Clone());
}
else
{
throw new ArgumentException($"BaseCurrency {baseCurrency} or QuoteCurrency{quoteCurrency} does not match Orderbook currencies!");
}
}
I have changed result = amountToConvert / price.Price;
我改变了result = amountToConvert / price.Price;
to result = amountToConvert / orderBook.Asks[0].Price;
result = amountToConvert / orderBook.Asks[0].Price;
without success.没有成功。
I have changed GetOrderBook()
in order to store an array copy rather than reference in the struct.我更改了GetOrderBook()
以便在结构中存储数组副本而不是引用。
There were two issues with the code:代码有两个问题:
As Charlieface mentioned in his first comment, array
is a reference type, not a value type.正如 Charlieface 在他的第一条评论中提到的, array
是引用类型,而不是值类型。 This caused updates in the Orderbook
to reflect in the SlimOrderbook
这导致Orderbook
中的更新反映在SlimOrderbook
Slimorderbook serves the purpose of providing a snapshot/copy of the orderbook for thread local processing. Slimorderbook 的目的是为线程本地处理提供订单簿的快照/副本。 Reference types in struct are still reference types and not copied as value type. struct 中的引用类型仍然是引用类型,而不是复制为值类型。
As it turns out, InvertedAsks
was updated from another thread in a non-atomic way.事实证明, InvertedAsks
是从另一个线程以非原子方式更新的。 (OrderBookPrice[])InvertedAsks.Clone()
hence copied an orderbook currently beeing updated. (OrderBookPrice[])InvertedAsks.Clone()
因此复制了当前正在更新的订单簿。
The issue can be fixed by first creating a new OrderBookPrice[]
, updating it and then replacing the reference in OrderBook
:这个问题可以通过首先创建一个新的OrderBookPrice[]
,更新它然后替换OrderBook
中的引用来解决:
OrderBookPrice[] newInvertedBids = new OrderBookPrice[Bids.Length];
for (int i = 0;i < Bids.Length;i++)
{
newInvertedBids[(Bids.Length-1)- i].Price = 1/Bids[i].Price;
newInvertedBids[(Bids.Length-1)- i].Volume = Bids[i].Volume;
}
InvertedAsks = newInvertedBids;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.