c# – 无锁,等待,独占访问方法

c# – 无锁,等待,独占访问方法,第1张

概述我有一个线程安全类,它使用需要独占访问的特定资源.在我的评估中,让各种方法的调用者在Monitor.Enter上阻塞或等待SemaphoreSlim以访问该资源是没有意义的. 例如,我有一些“昂贵的”异步初始化.由于多次初始化没有意义,无论是来自多个线程还是单个线程,多个调用应立即返回(甚至抛出异常).相反,应该创建,初始化然后将实例分发到多个线程. 更新1: MyClass在任一方向上使用两个N 我有一个线程安全类,它使用需要独占访问的特定资源.在我的评估中,让各种方法的调用者在Monitor.Enter上阻塞或等待SemaphoreSlim以访问该资源是没有意义的.

例如,我有一些“昂贵的”异步初始化.由于多次初始化没有意义,无论是来自多个线程还是单个线程,多个调用应立即返回(甚至抛出异常).相反,应该创建,初始化然后将实例分发到多个线程.

更新1:

MyClass在任一方向上使用两个namedPipes. InitBeforedistribute方法实际上并不是初始化,而是在两个方向上正确设置连接.在设置连接之前使管道可用于N个线程是没有意义的.一旦设置好,多个线程就可以发布工作,但只有一个线程可以实际读取/写入流.我很抱歉用这些例子命名不好来混淆这一点.

更新2:

如果InitBeforedistribute使用适当的等待逻辑(而不是引发异常的互锁 *** 作)实现了SemaphoreSlim(1,1),那么Add / Do Square方法是否正常?它不会抛出冗余异常(例如在InitBeforedistribute中),同时无锁?

以下是一个很好的例子:

class MyClass{    private int m_isIniting = 0; // exclusive access "lock"    private volatile bool vm_isInited = false; // vol. because other methods will read it    public async Task InitBeforedistribute()    {        if (Interlocked.Exchange(ref this.m_isIniting,-1) != 0)            throw new InvalIDOperationException(                "Cannot init concurrently! DID you distribute before init was finished?");        try        {            if (this.vm_isInited)                return;            await Task.Delay(5000)      // init asynchronously                .ConfigureAwait(false);            this.vm_isInited = true;        }        finally        {            Interlocked.Exchange(ref this.m_isConnecting,0);        }    }}

一些要点:

>如果存在阻止/等待锁访问的情况
完美的感觉,然后这个例子没有(有道理,那就是).
>因为我需要在方法中等待,所以我必须使用类似的东西
SemaphoreSlim如果我在哪里使用“正确的”锁.放弃了
上面例子的信号量让我不用担心
一旦我完成它就处理掉课程. (我总是不喜欢
处理多个线程使用的项目的想法.这是次要的
积极的,当然.)
>如果经常调用该方法,则可能会有一些性能
好处,当然应该衡量.

上面的例子在参考文献中没有意义.到(3.)所以这是另一个例子:

class MyClass{    private volatile bool vm_isInited = false; // see above example    private int m_isWorking = 0; // exclusive access "lock"    private Readonly ConcurrentQueue<Tuple<int,taskcompletionsource<int>> m_squareWork =        new ConcurrentQueue<Tuple<int,taskcompletionsource<int>>();    public Task<int> AddSquare(int number)    {        if (!this.vm_isInited) // see above example            throw new InvalIDOperationException(                "You forgot to init! DID you already distribute?");        var work = new Tuple<int,taskcompletionsource<int>(number,new taskcompletionsource<int>()        this.m_squareWork.Enqueue(work);        Task do = DoSquare();        return work.Item2.Task;    }    private async Task DoSquare()    {        if (Interlocked.Exchange(ref this.m_isWorking,-1) != 0)            return; // let someone else do the work for you        do        {            try            {                Tuple<int,taskcompletionsource<int> work;                while (this.m_squareWork.TryDequeue(out work))                {                    await Task.Delay(5000)      // limiting resource that can only be                        .ConfigureAwait(false); // used by one thread at a time.                    work.Item2.TrySetResult(work.Item1 * work.Item1);                }            }            finally            {                Interlocked.Exchange(ref this.m_isWorking,0);            }        } while (this.m_squareWork.Count != 0 &&            Interlocked.Exchange(ref this.m_isWorking,-1) == 0)    }}

这个“无锁”的例子中是否有一些具体的消极方面我应该注意什么?

与SO上的“无锁”代码相关的大多数问题通常都会提出反对意见,并指出它是针对“专家”的.很少(我可能在这个问题上错了)我是否可以看到人们可以深入研究的书籍/博客等等的建议,如果有人这么倾向的话.如果有任何此类资源我应该研究,请分享.任何建议将受到高度赞赏!

解决方法 更新:伟大的文章相关

.: Creating High-Performance Locks and Lock-free Code (for .NET) :.

>关于无锁algorythms的要点并不是它们适用于专家.
重点是你真的需要无锁的algorythm吗?我在这里无法理解你的逻辑:

Since it does not make sense to initialize more than once,whether it be from multiple threads or a single one,@H_502_63@multiple calls should return immediately (or even throw an exception).

为什么您的用户不能只是等待初始化的结果,并在此之后使用您的资源?如果可以的话,只需使用Lazy< T>.上课甚至是Asynchronous Lazy Initialization.
>你真的应该阅读关于consensus number和CAS-operations以及为什么在实现你自己的同步原语时这很重要.

在你的代码中,你使用的是Interlocked.Exchange方法,它实际上不是CAS,因为它总是交换值,并且它的共识数等于2.这意味着使用这种结构的原语只能用于2个线程(不是你的情况,但仍然是2).

我试图定义你的代码是否能正常运行3个线程,或者有些情况会导致你的应用程序处于损坏状态,但30分钟后我就停止了.在尝试理解您的代码之后,您的团队成员会像我一样停下来.这是浪费时间,不仅是你的,也是你的团队.在真正需要之前,不要重新发明轮子.
>我最喜欢的相关领域的书是Ben Watson的Writing High-Performance .NET Code,我最喜欢的博客是Stephen Cleary.如果您可以更具体地了解您感兴趣的书籍类型,我可以添加更多参考书.
>程序中没有锁定不会使您的应用程序无锁.在.NET应用程序中,您实际上不应该对内部程序流使用例外.考虑到 *** 作系统暂时没有安排初始化线程(基于各种原因,无论它们究竟是什么).

在这种情况下,应用程序中的所有其他线程将逐步尝试访问您的共享资源.我不能说这是一个无锁代码.是的,它没有锁,但它不能保证程序的正确性,因此根据定义它不是无锁的.

总结

以上是内存溢出为你收集整理的c# – 无锁,等待,独占访问方法全部内容,希望文章能够帮你解决c# – 无锁,等待,独占访问方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1231342.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存