我需要一个跨进程计数器。我可以在内存映射文件中映射一个整数并在其上使用Interlocked.Increment
,但在我看来Semaphore.Release
会做同样的事情并且编程开销较少。例如:
var mySem = new Semaphore(0, int.MaxValue, "mySemName");
// Get the next number.
int num = mySem.Release();
这看起来合理吗?
答案 0 :(得分:2)
简答:是的
但是......你必须增加(或减少它)才能阅读它。没有属性可以读取当前的插槽数(这是有道理的,因为它不是真正的用途)。
答案 1 :(得分:2)
不确定“rigmarole”是一个技术术语。减少开销?否。
信号量实现了一种特殊算法,以确保信号量计数器值在所有线程上保持一致。计数器值必须在检查之前锁定,并且锁定必须持续到计数器增量或减量完成为止。当它被锁定时,其他线程可能会等待(如果阻塞)或者只是失败(如果没有阻塞),有时会在稍后重试。
互锁增量仅确保增量操作是原子的。字节的互锁增量不需要任何特殊逻辑,因为逐字节增量是CPU级指令。根据芯片组,Word和DWord增量可能是也可能不是原子的;如果它是原子的,框架将利用它,如果不是,框架将设置一个锁,以确保不同的线程不会同时在同一个单词或双字内增加不同的内存部分
几乎所有的时间,互锁的增量和减量都会有更少的开销。
答案 2 :(得分:1)
是的,会正常工作。然而,这不是Semaphore课程的目的。可怜你身后的穷人来维护代码。他会想知道所有Semaphore.WaitOne()调用的位置。
在共享内存中做同样的事情并不难。这就是你所需要的......
string mapname = "{EE9D59F3-18F7-4FB6-B76B-AC1E6902BD9B}";
MemoryMappedFile mmf = MemoryMappedFile.CreateOrOpen(mapname, sizeof(int));
MemoryMappedViewAccessor mmva = mmf.CreateViewAccessor(0, sizeof(int));
int count = Interlocked.Increment(ref *(int*)p.ToPointer());
但这也不是值得骄傲的代码。您必须使用/ unsafe编译代码。
如果没有优雅的方法,那么你应该重新审视你的设计前提。为什么你首先需要一个共享柜台?如果要创建一些独特的东西,为什么不在每个进程中生成GUID?如果要聚合总计,则更强大的方法可能是将增量发布到服务器。如果你真的需要高性能计数,那么C#可能不适合你的野心。