C# 如何在信号量和信号量LIM之间进行选择?

C# 如何在信号量和信号量LIM之间进行选择?,c#,multithreading,semaphore,C#,Multithreading,Semaphore,它们的公共界面看起来很相似。声明信号量LIM是一个轻量级的替代方案,不使用Windows内核信号量。声明信号量lim要快得多。在什么情况下,信号量lim比信号量更有意义,反之亦然?一个区别是信号量lim不允许系统范围内的命名信号量。这意味着信号量LIM不能用于跨进程同步 还指出,当“等待时间预计非常短”时,应使用SemSlim。这通常会很好地符合这样一种观点,即对于大多数折衷方案来说,修身版更轻。描述了这一区别 一句话: SemaphoreSlim类表示一个轻量级、快速的信号量,当等待时间预计

它们的公共界面看起来很相似。声明信号量LIM是一个轻量级的替代方案,不使用Windows内核信号量。声明信号量lim要快得多。在什么情况下,信号量lim比信号量更有意义,反之亦然?

一个区别是
信号量lim
不允许系统范围内的命名信号量。这意味着信号量LIM不能用于跨进程同步

还指出,当“等待时间预计非常短”时,应使用SemSlim。这通常会很好地符合这样一种观点,即对于大多数折衷方案来说,修身版更轻。

描述了这一区别

一句话:

  • SemaphoreSlim类表示一个轻量级、快速的信号量,当等待时间预计很短时,它可以用于在单个进程内等待
关于“短时间”争议:

至少声明

SemaphoreSlim类是建议在单个应用程序中进行同步的信号量

在备注部分。同一节还介绍了信号量和信号量LIM之间的主要区别:

信号量LIM是不使用Windows内核信号量的信号量类的轻量级替代品。与Semaphore类不同,SemaphoreSlim类不支持命名系统信号量。您只能将其用作本地信号量


SemaphoreSlim基于SpinWait和Monitor,因此等待获取锁的线程正在消耗CPU周期一段时间,以期在屈服于另一个线程之前获取锁。如果没有发生这种情况,那么当操作系统再次调度线程时,线程允许系统切换上下文并重试(通过消耗一些CPU周期)。如果等待时间较长,这种模式可能会消耗大量CPU周期。因此,这种实现的最佳情况是,大部分时间没有等待时间,您几乎可以立即获得锁


信号量依赖于操作系统内核中的实现,因此每次获取锁时,都要花费大量的CPU周期,但之后线程只需休眠足够长的时间来获取锁

我查看了源代码,得出以下结论:

  • 信号量和信号量LIM都源自WaitHandle,它在内部使用Win32本机句柄。这就是为什么您需要同时处理()和()。因此,认为Slim是轻量级的说法值得怀疑

  • 信号量LIM在内部使用SpinWait,而信号量不使用。这告诉我,在等待时间很长的情况下,信号量应该做得更好,至少在不会阻塞CPU的意义上


  • 我希望MS写了一些关于等待时间不是“很短”时发生的事情。。。。或者“非常短”意味着什么取决于系统,1微秒用于信号量,1/4微秒用于信号量LIM进行等待或发布[“C#5.0简而言之”第890页],所以可能这就是他们所说的非常短的等待时间的意思?@dhsto很好的参考!但我猜链接文章的意思是“当访问共享资源的等待时间非常短时”——即资源不会长时间处于独占使用状态——而不是指信号量代码本身的等待时间?无论资源被锁定多长时间,信号量代码都将始终执行。@culix查看信号量与信号量LIM的源代码,我怀疑信号量LIM只应用于“非常短”的等待的主要原因是因为它使用旋转等待。这是更具响应性的,但会占用大量CPU,并且会浪费较长的等待时间,因为即时响应不太重要。信号量会阻塞线程。更多详细信息:
    [SemaphoreSlim和其他锁]在将线程置于真正的等待状态之前,会短暂使用busy spining。当等待时间预计很短时,旋转的计算成本远低于等待,因为等待需要昂贵的内核转换
    :要增加这一点,在所有情况下,如果应用程序是计算机上唯一需要访问该信号的进程,请使用信号量LIM。@Salgat为什么要这样做?如其他答案中所述,
    SemaphoreSlim
    是使用SpinWait实现的,因此如果您对它进行大量等待,将浪费大量CPU时间。如果您的进程是计算机上的唯一进程,这甚至不是一个好主意。从MSDN文档中可以看出,“SemaphoreSlim类是建议在单个应用程序中进行同步的信号量。”。除特殊情况外,如果只有一个进程使用该信号量,则应默认使用该信号量。对于任何并发数据类型,通常都存在特殊的异常,这是不言而喻的。信号量总是将作业传递给操作系统。这使得它相对昂贵,如果信号量没有强烈的竞争,内核调用很容易花费400纳秒。slim favor首先尝试使用一个共享变量以较低的成本实现这一点,仅在不起作用时才调用操作系统。你总是喜欢便宜,除了需要由多个进程共享信号量的情况。信号量lim不是从WaitHandle派生的。实际上,创建它的目的只有一个——在只需要在一个进程内同步操作的任务中,消除从WaitHandle派生的操作,WaitHandle是内核空间原语。