c# – 无锁,等待,独占访问方法
我有一个线程安全类,它使用需要独占访问的特定资源.在我的评估中,让各种方法的调用者在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); } } } 一些要点: >如果存在阻止/等待锁访问的情况 上面的例子在参考文献中没有意义.到(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的要点并不是它们适用于专家.
为什么您的用户不能只是等待初始化的结果,并在此之后使用您的资源?如果可以的话,只需使用Lazy< T>.上课甚至是 在你的代码中,你使用的是Interlocked.Exchange方法,它实际上不是CAS,因为它总是交换值,并且它的共识数等于2.这意味着使用这种结构的原语只能用于2个线程(不是你的情况,但仍然是2). 我试图定义你的代码是否能正常运行3个线程,或者有些情况会导致你的应用程序处于损坏状态,但30分钟后我就停止了.在尝试理解您的代码之后,您的团队成员会像我一样停下来.这是浪费时间,不仅是你的,也是你的团队.在真正需要之前,不要重新发明轮子. 在这种情况下,应用程序中的所有其他线程将逐步尝试访问您的共享资源.我不能说这是一个无锁代码.是的,它没有锁,但它不能保证程序的正确性,因此根据定义它不是无锁的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |