Multithreading 我可以混合搭配联锁增量和临界段吗?

Multithreading 我可以混合搭配联锁增量和临界段吗?,multithreading,delphi,Multithreading,Delphi,以前,我有这样的代码: EnterCriticalSection(q^); Inc(global_stats.currentid); LeaveCriticalSection(q^); EnterCriticalSection(q^); if (global_stats.currentid >= n) then begin LeaveCriticalSection(q^); Exit; end; LeaveCriticalSection(q

以前,我有这样的代码:

  EnterCriticalSection(q^);
  Inc(global_stats.currentid);
  LeaveCriticalSection(q^);
  EnterCriticalSection(q^);
  if (global_stats.currentid >= n) then
  begin
    LeaveCriticalSection(q^);
    Exit;
  end;
  LeaveCriticalSection(q^);
// thread A
InterlockedIncrement(global_stats.currentid);

....

// thread B
InterlockedIncrement(global_stats.currentid);

....

// thread C
if global_stats.currentid >= n then
  Exit;
我把它改成:

InterlockedIncrement(global_stats.currentid);
我发现有些代码是这样的:

  EnterCriticalSection(q^);
  Inc(global_stats.currentid);
  LeaveCriticalSection(q^);
  EnterCriticalSection(q^);
  if (global_stats.currentid >= n) then
  begin
    LeaveCriticalSection(q^);
    Exit;
  end;
  LeaveCriticalSection(q^);
// thread A
InterlockedIncrement(global_stats.currentid);

....

// thread B
InterlockedIncrement(global_stats.currentid);

....

// thread C
if global_stats.currentid >= n then
  Exit;
所以,问题是,我可以混合和匹配联锁增量并进入/离开临界区吗


哪个性能更快?临界和原子

不,一般来说你不能

临界段用于确保在所有受保护的代码块中,至多有一个在给定时刻执行。如果此类受保护的块访问
currentid
,并且该变量在另一个位置被修改,则代码可能无法正常工作

在特定的情况下,混合匹配是可以的,但是您必须检查所有受影响的代码并重新考虑处理过程,这样才能确保不会出现任何错误

我可以混合搭配联锁增量和进入/离开临界区吗

一般来说,不,你不能。关键部分和原子操作不相互作用

原子函数,如对
联锁增量的调用
,完全独立于关键部分和其他锁运行。也就是说,一个线程可以持有锁,另一个线程可以同时修改受保护的变量。与任何其他形式的互斥一样,关键部分只有在对共享数据进行操作的各方都持有锁时才起作用

然而,从您的代码中我们可以看到,在这种情况下,关键部分是不必要的。您可以这样编写代码:

  EnterCriticalSection(q^);
  Inc(global_stats.currentid);
  LeaveCriticalSection(q^);
  EnterCriticalSection(q^);
  if (global_stats.currentid >= n) then
  begin
    LeaveCriticalSection(q^);
    Exit;
  end;
  LeaveCriticalSection(q^);
// thread A
InterlockedIncrement(global_stats.currentid);

....

// thread B
InterlockedIncrement(global_stats.currentid);

....

// thread C
if global_stats.currentid >= n then
  Exit;
该代码在语义上等同于您以前的代码,其中包含一个关键部分


至于哪个性能更好,带锁的原始代码和上面没有锁的代码,后者的性能会更好。广义地说,无锁代码比使用锁的代码要好,但这不是一条可以依赖的规则。如果使用锁实现,某些算法可能比等效的无锁实现更快

@SergeyA InterlockedIncrement是为了避免增量上的经典比赛。如果只有两个线程,那么是的,您不需要它,因为只有一个writer。但是如果有两个写线程和一个读线程,那么您需要避免两个写线程之间的竞争。至于读取线程,它是在写入之前读取值,还是在写入之后读取值并不重要,只要它能够看到修改。语义与带锁的版本相同。@SergeyA好的,你有权发表你的意见,我尊重你的意见。然而,我认为,如果以x86为目标,依赖x86内存模型是合理的。是的,x64与x86具有相同的内存模型,而不是使用
如果全局统计数据.currentid>=n那么
,我更喜欢使用
如果InterlockedExchangeAdd(全局统计数据.currentid,0)>=n那么
@DavidHeffernan:我不相信这一点。如果变量没有正确对齐,或者多个CPU同时访问它,则不能保证它是原子读取。我更喜欢使用联锁API进行读写。