SemaphoreSlim(1,1)是否确保从缓存(如锁)中清除读写



额外问题

即使task1task2在两个不同的内核上运行,SemaphoreSlim(1, 1)是否仍然确保我有正确的输出1000000?

原始问题

考虑到以下代码片段,_semaphore是否具有与lock相同的效果?

输出:

  1. 使用锁:1000000
  2. _semaphore = new SemaphoreSlim(1, 1):1000000(我运行了10次程序,结果相同(
  3. _semaphore = new SemaphoreSlim(10, 10):从999998到999990到1000000不等,等等
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Calculate
{
private int _val = 0;
private object _addLock = new object();
private SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public int Val
{
get
{
return _val;
}
}
public void IncreManyTimes()
{
for (int i = 0; i < 500000; ++i)
{
//lock(_addLock)
//{
//    _val = _val + 1;
//}
_semaphore.Wait();
_val = _val + 1;
_semaphore.Release();
}
}
}
class Program
{
static void Main(string[] args)
{
Calculate calculate = new Calculate();
Task.Run(() =>
{
Task task1 = Task.Run(() =>
{
calculate.IncreManyTimes();
});
Task task2 = Task.Run(() =>
{
calculate.IncreManyTimes();
});
Task.WaitAll(task1, task2);
}).Wait();

Console.WriteLine(calculate.Val);
Console.ReadKey();
}
}
}

相关问题:锁定是否确保从缓存中清除读写?如果是,如何?

我的问题可以描述为:SemaphoreSlim(1, 1)是否确保从缓存中刷新读写?

_semaphore是否具有与lock相同的效果?

是和否。考虑到IncreManyTimes方法的行为,它确实具有相同的效果(_val = _val + 1;不会由多个线程同时运行(。

不过,他们也有一些不同。例如,lock总是专用于其执行线程,而SemaphoreSlim可以从任何线程释放。这就是为什么SemaphoreSlim是围绕包含await的代码块"锁定"的一个很好的选择(它甚至不会使用lock编译,因为如果在不同的线程上执行延续,它将无法按预期工作(。

需要进一步注意的是,如果lock内部存在异常,则锁定将被释放。为了达到同样的效果,您必须将_semaphore.Release();放入finally块中。

此外,SemaphorSlim是一个一次性对象,因此您应该考虑在Calculate类中实现IDisposable

最后,我不知道这是否只是一个简化的例子,但在这里你不需要任何这些。您可以简单地按Interlocked.Increment(ref _val)递增,这不需要锁定。

编辑:

即使task1task2在两个不同的cpu内核上运行,SemaphoreSlim(1, 1)是否仍能确保我有正确的输出1000000?

是的,因为它一次只允许关键部分中的一个线程。

信号量限制中的参数指定可以同时操作的线程数以及初始计数。如果您想使用信号量限制作为c#锁语句的等价物,那么支持的线程数必须为一。当你用10初始化你的sempahore时,你说最多有10个线程可以同时执行,这与锁不同。

信号量与刷新读写无关,这完全取决于信号量的使用方式。

如果要将其用作锁,则需要确保每次等待信号量时,它也会被释放,因此请使用try/finaly块。

相关内容

  • 没有找到相关文章

最新更新