附加问题
SemaphoreSlim(1, 1)
是否仍然确保我有正确的输出 1000000,即使 task1
和 task2
在 2 个不同的平台上运行核心?
原始问题
考虑以下代码片段,_semaphore
是否与 lock
具有相同的效果?
输出:
- 使用锁:1000000
_semaphore = new SemaphoreSlim(1, 1)
: 1000000(我运行程序10次结果都一样)_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();
}
}
}
相关问题:Does locking ensure reads and writes are flushed from caches? If so, how?
我的问题可以描述为:SemaphoreSlim(1, 1)
是否确保从缓存中刷新读取和写入?
最佳答案
does the
_semaphore
has the same effect aslock
?
是也不是。考虑到您的 IncreManyTimes
方法的行为,它确实具有相同的效果(_val = _val + 1;
不会由多个线程同时运行)。
不过,它们有一些不同。例如,lock
始终专用于其执行线程,而 SemaphoreSlim
可以从任何线程释放。这就是为什么 SemaphoreSlim
是“锁定”包含 await
的代码块的一个很好的替代方案(它甚至不会用 lock
编译)因为如果继续在不同的线程上执行,它将无法按预期工作。
进一步说明,如果lock
中出现异常,则锁会被释放。要达到相同的效果,您必须将 _semaphore.Release();
放在 finally
block 中。
此外,SemaphorSlim
是一次性对象,因此您应该考虑在您的Calculate
类中实现IDisposable
。
最后,我不知道这是否只是一个简化的示例,但在这里您不需要任何这些。您可以通过 Interlocked.Increment(ref _val)
简单地递增,不需要锁定。
编辑:
Does
SemaphoreSlim(1, 1)
still ensures that I have the correct output 1000000, even iftask1
andtask2
run on 2 different cpu cores?
是的,因为它一次只允许一个线程进入临界区。
关于c# - SemaphoreSlim(1, 1) 是否确保像锁一样从缓存中刷新读取和写入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71638590/