简体   繁体   中英

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:

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.
In case of the issue, OrderbookPrice price equates to the following:

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:

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

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:

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; to 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.

There were two issues with the code:

  1. As Charlieface mentioned in his first comment, array is a reference type, not a value type. This caused updates in the Orderbook to reflect in the SlimOrderbook

  2. Slimorderbook serves the purpose of providing a snapshot/copy of the orderbook for thread local processing. Reference types in struct are still reference types and not copied as value type.

As it turns out, InvertedAsks was updated from another thread in a non-atomic way. (OrderBookPrice[])InvertedAsks.Clone() hence copied an orderbook currently beeing updated.

The issue can be fixed by first creating a new OrderBookPrice[] , updating it and then replacing the reference in 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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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