假设一个类有一个public int counter由多个线程访问的字段.这int只是递增或递减.
要增加此字段,应使用哪种方法,为什么?
lock(this.locker) this.counter++;,Interlocked.Increment(ref this.counter);,counter为public volatile.现在,我发现volatile,我已经删除了许多lock语句和使用Interlocked.但是有理由不这样做吗?
只是检查...... _count正在安全访问,对吗?
两个方法都由多个线程访问.
private int _count;
public void CheckForWork() {
if (_count >= MAXIMUM) return;
Interlocked.Increment(ref _count);
Task t = Task.Run(() => Work());
t.ContinueWith(CompletedWorkHandler);
}
public void CompletedWorkHandler(Task completedTask) {
Interlocked.Decrement(ref _count);
// Handle errors, etc...
}
Run Code Online (Sandbox Code Playgroud) Microsoft提供了InterlockedCompareExchange执行原子比较和交换操作的功能.还有一个内在的._InterlockedCompareExchange
在x86上,这些是使用lock cmpxchg指令实现的.
但是,通过阅读这三种方法的文档,他们似乎并不同意对齐要求.
英特尔的参考手册没有说明对齐(除了如果启用了对齐检查并且进行了未对齐的内存引用,则会生成异常)
我也查找了lock前缀,具体说明了这一点
锁定前缀的完整性不会受到内存领域的对齐方式.
(强调我的)
所以英特尔似乎认为对齐是无关紧要的.无论如何,这个操作都是原子的.
该_InterlockedCompareExchange固有的文档也只字未提对齐,但是InterlockedCompareExchange 功能指出,
该函数的参数必须在32位边界上对齐; 否则,该函数将在多处理器x86系统和任何非x86系统上表现不可预测.
什么给出了什么?对齐要求是否InterlockedCompareExchange只是为了确保该功能即使在cmpxchg指令不可用的486之前的CPU上也能正常工作?这看起来很可能基于上述信息,但在依赖它之前我想确定一下.:)
或者ISA需要对齐以保证原子性,我只是在英特尔的参考手册中找错了地方?
(这是重复:如何正确读取Interlocked.Increment'ed int字段?但是,在阅读了答案和评论之后,我仍然不确定正确的答案.)
有些代码我不拥有,也无法更改为使用在几个不同线程中增加int计数器(numberOfUpdates)的锁.所有通话都使用:
Interlocked.Increment(ref numberOfUpdates);
Run Code Online (Sandbox Code Playgroud)
我想在我的代码中读取numberOfUpdates.既然这是一个int,我知道它不会撕裂.但是,确保我获得最新价值的最佳方法是什么?看起来我的选择是:
int localNumberOfUpdates = Interlocked.CompareExchange(ref numberOfUpdates, 0, 0);
Run Code Online (Sandbox Code Playgroud)
要么
int localNumberOfUpdates = Thread.VolatileRead(numberOfUpdates);
Run Code Online (Sandbox Code Playgroud)
两者都有效(无论优化,重新排序,缓存等,都可以提供最新的价值)?一个比另一个更受欢迎吗?还有第三种选择更好吗?
假设:
A. WIN32下的C++.
B.正确对齐的易失性整数使用InterlockedIncrement()和递增和递减InterlockedDecrement().
__declspec (align(8)) volatile LONG _ServerState = 0;
Run Code Online (Sandbox Code Playgroud)
如果我想简单地读取_ServerState,我是否需要通过InterlockedXXX函数读取变量?
例如,我见过如下代码:
LONG x = InterlockedExchange(&_ServerState, _ServerState);
Run Code Online (Sandbox Code Playgroud)
和
LONG x = InterlockedCompareExchange(&_ServerState, _ServerState, _ServerState);
Run Code Online (Sandbox Code Playgroud)
目标是简单地读取当前的值_ServerState.
我不能简单地说:
if (_ServerState == some value)
{
// blah blah blah
}
Run Code Online (Sandbox Code Playgroud)
这个问题似乎有些混乱.我理解在Windows中注册大小的读取是原子的,所以我认为这个InterlockedXXX函数是不必要的.
马特J.
好的,谢谢你的回复.顺便说一句,这是Visual C++ 2005和2008.
如果这是真的,我应该使用一个InterlockedXXX函数来读取它的值_ServerState,即使只是为了清楚起见,最好的方法是什么?
LONG x = InterlockedExchange(&_ServerState, _ServerState);
Run Code Online (Sandbox Code Playgroud)
这具有修改值的副作用,当我真正想做的就是阅读它.不仅如此,如果存在上下文切换,我可以将标志重置为错误的值,因为_ServerState在准备调用时将值推到堆栈上InterlockedExchange().
LONG x = InterlockedCompareExchange(&_ServerState, _ServerState, _ServerState);
Run Code Online (Sandbox Code Playgroud)
我从我在MSDN上看到的一个例子中得到了这个.
见http://msdn.microsoft.com/en-us/library/ms686355(VS.85).aspx
我所需要的只是一条线:
lock mov …Run Code Online (Sandbox Code Playgroud) 是Interlocked.Increment(ref x)不是更快或更慢x++的在各种平台上整数和长?
该System.Threading.Interlocked对象允许加法(减法)和比较作为原子操作.似乎只是不做相等的CompareExchange以及作为原子比较的GreaterThan/LessThan将是非常有价值的.
Interlocked.GreaterThanIL 的假设特征还是CPU级功能?都?
缺少任何其他选项,是否可以用C++或直接IL代码创建这样的功能并将该功能公开给C#?
忽略了片刻的荒谬await荷兰国际集团的Enumerable.Range电话.只是在那里引发崩溃行为.它就像一个方法,可以做一些网络IO来构建一个值对象的集合.(的确,这是我看到崩溃发生的地方.)
如果我注释掉该Interlocked.Exchange行,编译器不会崩溃.
public class Launcher
{
private static IEnumerable<int> _foo;
static void Main(string[] args)
{
DoWorkAsync().Wait();
}
private static async Task DoWorkAsync()
{
RefreshCache();
foreach (var element in _foo)
{
Console.WriteLine(element);
}
Console.ReadLine();
}
private static async void RefreshCache()
{
Interlocked.Exchange(ref _foo, await Cache());
}
private static async Task<IEnumerable<int>> Cache()
{
return Enumerable.Range(0, 10);
}
}
Run Code Online (Sandbox Code Playgroud)
更改RefreshCache()为此可防止编译器崩溃:
private static async void RefreshCache()
{
var foo = await Cache();
Interlocked.Exchange(ref _foo, foo);
} …Run Code Online (Sandbox Code Playgroud) Win32 api有一组InterlockedXXX函数可以原子地和同步地操作简单变量,但是似乎没有任何InterlockedRead函数可以简单地检索变量的值.怎么会?
对正确对齐的32位变量的简单读取和写入是原子操作
但补充说:
但是,不保证访问同步.但是,不保证访问同步.如果两个线程正在从同一个变量读取和写入,则无法确定一个线程是否会在另一个线程执行其写入操作之前执行其读取操作.
这意味着,据我所知,变量的简单读取操作可以发生,而另一个,例如,InterlockedAdd操作就位.那么为什么没有互锁函数来读取变量呢?
我猜这个值可以作为InterlockedAdd-zero的结果读取,但这似乎不是正确的方法.
Interlocked.Increment 似乎是在多线程代码中需要执行的最标准/最简单的操作之一.
我假设该方法的功能是一种排序模式,任何具有线程经验的人都能够复制.
所以基本上我想知道的是,如果某人能够提供Interlocked.Increment内部实际执行的方法的完全重复(解释它是如何工作的)?(我已经找到了实际方法的来源但却无法找到它)
interlocked ×10
c# ×6
.net ×2
c++ ×2
locking ×2
winapi ×2
async-await ×1
atomic ×1
compiler-bug ×1
il ×1
performance ×1
volatile ×1
windows ×1
x86 ×1