(这是重复:如何正确读取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)
两者都有效(无论优化,重新排序,缓存等,都可以提供最新的价值)?一个比另一个更受欢迎吗?还有第三种选择更好吗?
是Interlocked.Increment(ref x)不是更快或更慢x++的在各种平台上整数和长?
该System.Threading.Interlocked对象允许加法(减法)和比较作为原子操作.似乎只是不做相等的CompareExchange以及作为原子比较的GreaterThan/LessThan将是非常有价值的.
Interlocked.GreaterThanIL 的假设特征还是CPU级功能?都?
缺少任何其他选项,是否可以用C++或直接IL代码创建这样的功能并将该功能公开给C#?
我想从多个线程递增无符号整数.
我知道Interlocked.Increment,但它不处理无符号整数.我可以使用lock(),但出于性能原因我不愿意.
它只是以正常方式增加它的线程安全吗?如果偶尔的增量丢失也没关系,因为它只用于统计.我不想要的是腐败的价值.
最近我从VB转到C#,所以我经常使用C#到VB.NET转换器来理解语法差异.在将下一个方法移动到VB时,我发现了一个有趣的事情
C#原始代码:
public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
{
int trueCnt = 0;
foreach(bool b in bools)
if (b && (++trueCnt > threshold))
return true;
return false;
}
Run Code Online (Sandbox Code Playgroud)
VB.NET结果:
Public Function ExceedsThreshold(threshold As Integer, bools As IEnumerable(Of Boolean)) As Boolean
Dim trueCnt As Integer = 0
For Each b As Boolean In bools
If b AndAlso (System.Threading.Interlocked.Increment(trueCnt) > threshold) Then
Return True
End If
Next
Return False End Function
Run Code Online (Sandbox Code Playgroud)
C#的++运算符被替换为System.Threading.Interlocked.Increment
是否意味着++如果在foreach循环中使用,线程安全运算符不会成为线程安全的?它是一种语法糖吗?如果这是真的,那么为什么转换器放在Interlocked.IncrementVB版本中?我认为C#和VB中的foreach完全相同.或者它只是一个转换器"保险"?
写另一个问题的答案出现了一些有趣的事情,现在我无法理解Interlocked.Increment(ref long value)32位系统是如何工作的.让我解释.
InterlockedIncrement64在编译32位环境时,Native 现在不可用了,好吧,这是有道理的,因为在.NET中你不能根据需要对齐内存,可以从托管调用然后删除它.
在.NET我们可以调用Interlocked.Increment()与对64位的变量的引用,我们仍然没有关于其对齐的任何约束(例如,在一个结构中,也在这里我们可以使用FieldOffset和StructLayout),但文献中没有提到任何限制(AFAIK ).这很神奇,它有效!
Hans Passant注意到这Interlocked.Increment()是JIT编译器识别的一种特殊方法,它将发出对 COMInterlocked :: ExchangeAdd64()的调用,然后调用FastInterlockExchangeAddLong,它是InterlockedExchangeAdd64的一个宏,它具有InterlockedIncrement64的相同限制.
现在我很困惑.
忘记一秒钟的托管环境,然后回归原生.为什么InterlockedIncrement64不能工作InterlockedExchangeAdd64呢?InterlockedIncrement64是一个宏,如果内在函数不可用,InterlockedExchangeAdd64那么它可以实现为InterlockedExchangeAdd64... 的调用
让我们回到托管:如何在32位系统上实现原子64位增量?我认为句子"这个函数对于调用其他互锁函数是原子的"很重要,但我仍然没有看到任何代码(感谢Hans指出更深入的实现)来做到这一点.InterlockedExchangedAdd64当内在函数不可用时,让我们从WinBase.h中选择实现:
FORCEINLINE
LONGLONG
InterlockedExchangeAdd64(
_Inout_ LONGLONG volatile *Addend,
_In_ LONGLONG Value
)
{
LONGLONG Old;
do {
Old = *Addend;
} while (InterlockedCompareExchange64(Addend, …Run Code Online (Sandbox Code Playgroud) 请原谅我略带幽默的头衔.我在其中使用了两个不同的"安全"一词(显然).
我对线程很陌生(好吧,我已经使用了多年的线程,但只有非常简单的形式).现在我面临着编写某些算法的parallal实现的挑战,并且线程需要处理相同的数据.考虑以下新手错误:
const
N = 2;
var
value: integer = 0;
function ThreadFunc(Parameter: Pointer): integer;
var
i: Integer;
begin
for i := 1 to 10000000 do
inc(value);
result := 0;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
threads: array[0..N - 1] of THandle;
i: Integer;
dummy: cardinal;
begin
for i := 0 to N - 1 do
threads[i] := BeginThread(nil, 0, @ThreadFunc, nil, 0, dummy);
if WaitForMultipleObjects(N, @threads[0], true, INFINITE) = WAIT_FAILED then
RaiseLastOSError;
ShowMessage(IntToStr(value));
end;
Run Code Online (Sandbox Code Playgroud)
初学者可能希望上面的代码显示消息20000000.实际上,首先value是等于0 …
delphi multithreading thread-safety critical-section interlocked-increment
我们有一个方法可以维护应用程序中所有事件的全局序列索引.因为它是网站,所以预计这种方法线程安全.线程安全实现如下:
private static long lastUsedIndex = -1;
public static long GetNextIndex()
{
Interlocked.Increment(ref lastUsedIndex);
return lastUsedIndex;
}
Run Code Online (Sandbox Code Playgroud)
但是我们注意到在一些不重负载的情况下,系统中出现了重复索引.简单测试显示,对于100000次迭代,大约有1500个重复项.
internal class Program
{
private static void Main(string[] args)
{
TestInterlockedIncrement.Run();
}
}
internal class TestInterlockedIncrement
{
private static long lastUsedIndex = -1;
public static long GetNextIndex()
{
Interlocked.Increment(ref lastUsedIndex);
return lastUsedIndex;
}
public static void Run()
{
var indexes = Enumerable
.Range(0, 100000)
.AsParallel()
.WithDegreeOfParallelism(32)
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.Select(_ => GetNextIndex())
.ToList();
Console.WriteLine($"Total values: {indexes.Count}");
Console.WriteLine($"Duplicate values: {indexes.GroupBy(i => i).Count(g => g.Count() > …Run Code Online (Sandbox Code Playgroud) 有人可以帮助解释c ++中互锁变量访问和关键部分互锁增量之间的差异吗?非常感谢,提前谢谢.
我有一个多线程应用程序(C++),我需要增加/更改一系列值.如果我使用一系列互锁操作,它们被认为是单个原子操作吗?就像在这个例子中:
InterlockedIncrement(&value1);
InterlockedIncrement(&value2);
InterlockedExchange(&oldValue, newValue);
Run Code Online (Sandbox Code Playgroud)
或者我们更好地锁定以执行同步?像这样:
EnterCriticalSection(&cs);
value1++;
value2++;
oldValue = newValue;
LeaveCriticalSection(&cs);
Run Code Online (Sandbox Code Playgroud)
我认为需要一个锁定,但我不确定......所有的值要么处于旧状态,要么处于新状态,这一点非常重要.