十进制线程安全性,适用于一个写入线程和多个读取线程

23 浏览
0 Comments

十进制线程安全性,适用于一个写入线程和多个读取线程

我想更多地了解某个问题的确切行为,以便我可以决定是否使用lock(以及它的性能影响)。\n给定以下伪代码:\n

class Thread1
{
    public decimal TotalValue {get; private set;}
    private decimal StockAmount;
    private decimal OldPrice;
    public async Task GetStockPrices(string fictionalAsset)
    {
        while (true)
        {
            decimal totalCopy = TotalValue;
            totalCopy -= (StockAmount * OldPrice);
            OldPrice = StockPrices.GetValue(fictionalAsset);
            totalCopy += (StockAmount * OldPrice);
            TotalValue = totalCopy;
        }
    }
}

\n假设Thread1是唯一修改TotalValue的线程。所有其他线程(无论其数量如何)只能从中读取。\n当然,可能发生这样的情况,即一个读取线程在TotalValue = totalCopy;时访问TotalValue。\n这会有什么影响?读取线程是否只会收到TotalValue的旧版本(正常),还是可能有其他不希望的结果(如0或任何其他数字-致命错误)?还有其他影响,比如性能或其他线程的更新时间?\n我希望上述代码比以下代码更高效:\n

lock (TotalLock)
{
    TotalValue = totalCopy;
}

\n特别是由于读取线程可能很多且频繁,有效地锁定值。\n如果需要锁定,锁是如何提供的?(我想象先进先出或随机)-可以为写入线程分配优先级吗?(检查变量是否被锁定,如果是,则等待)

0
0 Comments

问题:在具有一个写线程和多个读线程的情况下,实现对Decimal类型的线程安全。

原因:需要实现一个线程安全的TotalValue属性,其中读操作(get)可以被多个线程同时执行,而写操作(set)只能由一个线程执行。使用lock关键字可以实现线程安全,但是如果读操作远远多于写操作,使用锁的开销会成为性能瓶颈。

解决方法:可以通过将Decimal类型的值封装在Tuple或StrongBox中,使用volatile关键字确保多个线程对值的可见性。但是,如果频繁更新TotalValue属性,会导致大量的短暂Tuple实例被垃圾回收,从而抵消了避免同步开销的好处。

为了减少垃圾回收,可以使用一个可重用的引用容器。可以使用一个环形数组来存储Decimal类型的值,确保数组足够大,以便其他线程有足够的时间读取旧值。然后,将TotalValue属性的引用替换为环形数组中当前写入的值。

需要注意的是,这种解决方法仅适用于只有一个写线程的场景。对于多个写线程的情况,需要同步访问环形数组。

通过使用Tuple或StrongBox封装Decimal类型的值,并使用volatile关键字确保多个线程对值的可见性,可以实现一个在一个写线程和多个读线程之间的线程安全的TotalValue属性。使用环形数组可以减少垃圾回收的开销,提高性能。然而,这种解决方法仅适用于只有一个写线程的情况。对于多个写线程,需要同步访问环形数组。

0