简体   繁体   English

复制结构会导致空结构

[英]Copying a struct results in empty struct

Issue:问题:

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:这是我的调试视图的屏幕截图: 截屏

Underlying functions:底层函数:

The two mainly involved Data structures are class Orderbook and struct SlimOrderbook主要涉及的两个数据结构分别是class Orderbookstruct 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!");
    }
}

Attempted Fixes:尝试修复:

  • 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:代码有两个问题:

  1. 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

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM