繁体   English   中英

如何正确使用Interlocked.Add()?

[英]How do I use Interlocked.Add() correctly?

此处的文档:“此类的方法有助于防止在线程更新可由其他线程访问的变量时调度程序切换上下文时可能发生的错误...”

此外, 这个问题的答案表明“联锁方法对任何数量的核心或CPU都是同时存在的”,这似乎很清楚。

基于上面我认为Interlocked.Add()足以让多个线程对变量进行添加。 显然我错了或者我使用的方法不正确。 在下面的runnable代码中,我希望当Run()完成时,Downloader.ActiveRequestCount为零。 如果我没有锁定对Interlocked.Add的调用,我会得到一个随机的非零结果。 Interlocked.Add()的正确用法是什么?

class Program
{
    private Downloader downloader { get; set; }

    static void Main(string[] args)
    {
        new Program().Run().Wait();
    }


    public async Task Run()
    {
        downloader = new Downloader();
        List<Task> tasks = new List<Task>(100);

        for (int i = 0; i < 100; i++)
            tasks.Add(Task.Run(Download));

        await Task.WhenAll(tasks);

        Console.Clear();
        //expected:0, actual when lock is not used:random number i.e. 51,115
        Console.WriteLine($"ActiveRequestCount is : {downloader.ActiveRequestCount}"); 
        Console.ReadLine();


    }

    private async Task Download()
    {
        for (int i = 0; i < 100; i++)
            await downloader.Download();
    }
}

public class Downloader :INotifyPropertyChanged
{
    private object locker = new object();
    private int _ActiveRequestCount;
    public int ActiveRequestCount { get => _ActiveRequestCount; private set => _ActiveRequestCount = value; }

    public async Task<string> Download()
    {
        string result = string.Empty;

        try
        {
            IncrementActiveRequestCount(1);
            result = await Task.FromResult("boo");
        }
        catch (Exception ex)
        {
            Console.WriteLine("oops");
        }
        finally
        {
            IncrementActiveRequestCount(-1);
        }

        return result;
    }


    public void IncrementActiveRequestCount(int value)
    {
        //lock (locker)       // is this redundant
        //{
            _ActiveRequestCount = Interlocked.Add(ref _ActiveRequestCount, value);
        //}

        RaisePropertyChanged(nameof(ActiveRequestCount));
    }

    #region INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged([CallerMemberNameAttribute] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    #endregion
}

更换

_ActiveRequestCount = Interlocked.Add(ref _ActiveRequestCount, value);

Interlocked.Add(ref _ActiveRequestCount, value);

Interlocked.Add是线程安全的并且接受ref参数,因此它可以安全地进行分配。 另外执行(不必要的)不安全的分配( = )。 只需删除它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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