Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 使用'安全吗;不安全';线程函数?_Multithreading_Delphi_Thread Safety_Critical Section_Interlocked Increment - Fatal编程技术网

Multithreading 使用'安全吗;不安全';线程函数?

Multithreading 使用'安全吗;不安全';线程函数?,multithreading,delphi,thread-safety,critical-section,interlocked-increment,Multithreading,Delphi,Thread Safety,Critical Section,Interlocked Increment,请原谅我略带幽默的标题。我对“安全”一词使用了两种不同的定义(显然) 我对线程技术相当陌生(好吧,我已经使用线程技术很多年了,但只是非常简单的形式)。现在我面临着编写一些算法的视差实现的挑战,线程需要处理相同的数据。考虑下面的新手错误: const N = 2; var value: integer = 0; function ThreadFunc(Parameter: Pointer): integer; var i: Integer; begin for i :=

请原谅我略带幽默的标题。我对“安全”一词使用了两种不同的定义(显然)

我对线程技术相当陌生(好吧,我已经使用线程技术很多年了,但只是非常简单的形式)。现在我面临着编写一些算法的视差实现的挑战,线程需要处理相同的数据。考虑下面的新手错误:

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;
初学者可能希望上面的代码显示消息
20000000
。实际上,首先
value
等于
0
,然后我们
inc
it
20000000
次。但是,由于
inc
过程不是“原子的”,两个线程将发生冲突(我猜
inc
执行三件事:读取、递增和保存),因此许多
inc
将实际上“丢失”。我从上面的代码中得到的典型值是
10030423

最简单的解决方法是使用而不是(在这个愚蠢的示例中,这会慢得多,但这不是重点)。另一个解决方法是将
inc
放在一个关键部分内(是的,在这个愚蠢的示例中,这也会非常慢)

现在,在大多数实际算法中,冲突并不常见。事实上,它们可能非常罕见。我的一个算法创建了一个变量,其中一个变量是吸附粒子的数量。这里的冲突非常罕见,更重要的是,我真的不在乎变量的总和是20000000、2000008、20000319还是19999496。因此,不使用
InterlockedIncrement
或critical部分是很有诱惑力的,因为它们只会使代码膨胀,并使代码(稍微)变慢到没有(据我所见)好处

然而,我的问题是:冲突的后果会比递增变量的值稍微“不正确”更严重吗?例如,程序会崩溃吗


诚然,这个问题可能看起来很愚蠢,因为毕竟,使用
InterlockedIncrement
而不是
inc
的成本相当低(在许多情况下,但不是全部!),因此(也许)不谨慎行事是愚蠢的。但是我也觉得知道这在理论层面上是如何工作的会很好,所以我仍然认为这个问题很有趣。

你的程序不会因为一个只用作计数的整数增量的竞争而崩溃。唯一可能出错的是你没有得到正确的答案。显然,如果您使用整数作为数组的索引,或者它可能是指针,那么您可能会遇到问题

除非您以难以置信的频率递增该值,否则很难想象联锁递增的成本会高到足以让您注意到性能差异


更有效的方法是让每个线程维护自己的私有计数。然后在计算结束时加入线程时,求和所有单个线程计数。这样你就能两全其美。没有关于递增和正确答案的争论。当然,您需要采取措施确保自己不会被发现。

谢谢您的回答。关于最后一部分,我知道这是一个愚蠢的例子,但我只是想证实我的假设,即在这种情况下可能发生的最糟糕的事情是明显错误(或“稍微偏离”)的结果。风险当然也取决于你对该计数的处理。如果它仅用于显示,这是没有问题的,但如果您将其用于迭代或其他内容,其中错误的计数可能意味着内存泄漏或访问已被删除的内存,则可能会出现问题deallocated@Andreas我们就是忍不住要扩大这个问题@大卫:也许我应该补充一点说明,我确实知道这个程序可以简化为
ShowMessage('20000000')
!还有一个+15!再次感谢!我猜投票被否决是因为这个幽默的标题。