C# 我可以使用'Semaphore.Release'作为现成的互锁增量吗?

C# 我可以使用'Semaphore.Release'作为现成的互锁增量吗?,c#,.net,concurrency,multiprocessing,interlocked,C#,.net,Concurrency,Multiprocessing,Interlocked,我需要一个交叉进程计数器。我可以在内存映射文件中映射一个整数,并在其上使用Interlocked.Increment,但在我看来,信号量.Release也可以做同样的事情,并且编程开销更少。例如: var mySem = new Semaphore(0, int.MaxValue, "mySemName"); // Get the next number. int num = mySem.Release(); 这看起来合理吗?简短的回答:是的 但是。。。你必须递增(或递减)才能读取它。没有读

我需要一个交叉进程计数器。我可以在内存映射文件中映射一个整数,并在其上使用
Interlocked.Increment
,但在我看来,
信号量.Release
也可以做同样的事情,并且编程开销更少。例如:

var mySem = new Semaphore(0, int.MaxValue, "mySemName");

// Get the next number.
int num = mySem.Release();
这看起来合理吗?

简短的回答:是的

但是。。。你必须递增(或递减)才能读取它。没有读取当前插槽数量的属性(这是有意义的,因为它们不是真正的用途)

简短回答:是的

但是。。。你必须递增(或递减)才能读取它。没有读取当前插槽数量的属性(这是有意义的,因为它们不是真正的用途)

不确定“繁琐”是否是一个专业术语。用更少的开销?没有

信号量实现一个特殊的算法,以确保信号量计数器值在所有线程上保持一致。在检查计数器值之前,必须将其锁定,并且锁定必须持续到计数器递增或递减完成。当它被锁定时,其他线程可能会等待(如果阻塞)或干脆失败(如果不阻塞),有时会稍后重试

联锁增量仅确保增量操作是原子的。字节的联锁增量不需要任何特殊逻辑,因为字节增量是CPU级指令。字和双字增量可能是原子增量,也可能不是原子增量,具体取决于芯片组;如果它是原子的,框架将利用它,如果不是,框架将设置一个锁,以确保不同线程不会同时增加同一单词或dword中的不同内存部分

几乎在所有的时间里,互锁的增量和减量的开销都会小得多。

不确定“繁琐”是否是一个技术术语。用更少的开销?没有

信号量实现一个特殊的算法,以确保信号量计数器值在所有线程上保持一致。在检查计数器值之前,必须将其锁定,并且锁定必须持续到计数器递增或递减完成。当它被锁定时,其他线程可能会等待(如果阻塞)或干脆失败(如果不阻塞),有时会稍后重试

联锁增量仅确保增量操作是原子的。字节的联锁增量不需要任何特殊逻辑,因为字节增量是CPU级指令。字和双字增量可能是原子增量,也可能不是原子增量,具体取决于芯片组;如果它是原子的,框架将利用它,如果不是,框架将设置一个锁,以确保不同线程不会同时增加同一单词或dword中的不同内存部分


几乎在所有的时间里,互锁的增量和减量的开销都会小得多。

是的,可以正常工作。然而,这并不是信号量类设计的目的。可怜那个在你后面维护代码的可怜的家伙。他会想知道所有的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#不是你实现抱负的合适工具。

是的,它可以很好地工作。然而,这并不是信号量类设计的目的。可怜那个在你后面维护代码的可怜的家伙。他会想知道所有的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#不是你实现抱负的合适工具。

@ScottChamberlain,我认为这是不对的<代码>释放递增,而
WaitOne
递减。“我刚刚在林帕德测试过它。”“斯科特汉姆伯伦,我认为这不对<代码>释放递增,而
WaitOne
递减。我刚刚在LINQPad中测试了它。
Release
递增计数器返回上一个值。@dan gph这是我的观点。要使其用作计数器,您可能需要能够在不修改值的情况下读取计数器。但出于我的需要,我只需要在计数器递增时读取计数器一次。
Release
递增计数器返回以前的值。@dan gph这是我的观点。为了使它成为一个有用的计数器,您可能需要在不修改valueGood point的情况下读取它,但出于我的需要,我只需要在计数器递增时读取一次计数器。我不关心处理器开销。我只关心编程开销。看,我还以为你只关心繁文缛节。对不起,我应该更精确一些。我把它改为“编程开销”。我不关心处理器开销。我只关心编程开销。看,我还以为你只关心繁文缛节。对不起,我应该更精确一些。我把它改为“编程开销”。谢谢。我不知道