SemaphoreSlim(1, 1) 是否确保像锁一样从缓存中刷新读取和写入?
Does SemaphoreSlim(1, 1) ensures read and writes are flushed from caches like lock?
附加问题
即使 task1
和 task2
运行 在 2 个不同的内核上,SemaphoreSlim(1, 1)
是否仍然确保我有正确的输出 1000000?
原问题
考虑以下代码片段,_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)
是否确保从缓存中清除读取和写入?
semaphoreslim中的参数指定了多少个线程可以并发运行,初始计数是多少。如果要使用 semaphoreslim 作为 c# lock 语句的等价物,那么支持的线程数 必须 为一个。当你用 10 初始化你的 sempahore 时,你是说最多 10 个线程可以同时执行,这与锁不同。
信号量与刷新读取或写入无关,这完全取决于您如何使用信号量。
如果你打算将它用作锁,你需要确保每次等待信号量时,它也会被释放,所以使用 try/finally 块。
does the _semaphore
has the same effect as lock
?
是也不是。考虑到您的 IncreManyTimes
方法的行为,它确实具有相同的效果(_val = _val + 1;
不会被多个线程同时 运行)。
不过,它们有一些不同。例如,lock
始终专用于其执行线程,而 SemaphoreSlim
可以从任何线程释放。这就是为什么 SemaphoreSlim
是 'locking' 围绕包含 await
的代码块的一个很好的替代方案(它甚至不会用 lock
编译,因为它不会按预期工作如果延续在不同的线程上执行)。
进一步说明,如果lock
内部出现异常,则锁被释放。要达到相同的效果,您必须将 _semaphore.Release();
放在 finally
块中。
此外,SemaphorSlim
是一次性对象,因此您应该考虑在 Calculate
class.
中实施 IDisposable
最后,我不知道这是否只是一个简化的示例,但在这里您不需要任何这些。您可以简单地增加 Interlocked.Increment(ref _val)
,这不需要锁定。
编辑:
Does SemaphoreSlim(1, 1)
still ensures that I have the correct output 1000000, even if task1
and task2
run on 2 different cpu cores?
是的,因为它一次只允许临界区中有一个线程。
附加问题
即使 task1
和 task2
运行 在 2 个不同的内核上,SemaphoreSlim(1, 1)
是否仍然确保我有正确的输出 1000000?
原问题
考虑以下代码片段,_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)
是否确保从缓存中清除读取和写入?
semaphoreslim中的参数指定了多少个线程可以并发运行,初始计数是多少。如果要使用 semaphoreslim 作为 c# lock 语句的等价物,那么支持的线程数 必须 为一个。当你用 10 初始化你的 sempahore 时,你是说最多 10 个线程可以同时执行,这与锁不同。
信号量与刷新读取或写入无关,这完全取决于您如何使用信号量。
如果你打算将它用作锁,你需要确保每次等待信号量时,它也会被释放,所以使用 try/finally 块。
does the
_semaphore
has the same effect aslock
?
是也不是。考虑到您的 IncreManyTimes
方法的行为,它确实具有相同的效果(_val = _val + 1;
不会被多个线程同时 运行)。
不过,它们有一些不同。例如,lock
始终专用于其执行线程,而 SemaphoreSlim
可以从任何线程释放。这就是为什么 SemaphoreSlim
是 'locking' 围绕包含 await
的代码块的一个很好的替代方案(它甚至不会用 lock
编译,因为它不会按预期工作如果延续在不同的线程上执行)。
进一步说明,如果lock
内部出现异常,则锁被释放。要达到相同的效果,您必须将 _semaphore.Release();
放在 finally
块中。
此外,SemaphorSlim
是一次性对象,因此您应该考虑在 Calculate
class.
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?
是的,因为它一次只允许临界区中有一个线程。