2015-07-23 2 views
0

Является ли этот код потокобезопасным или FCount может быть изменен другим потоком до выполнения InterLockedDecrement?Threadsafe test/декремент

procedure TMyObject.Wait; 
begin 
    if FCount > 0 then 
    InterLockedDecrement(FCount); 
    .. 
end; 
+0

Посмотреть исходный код из [SyncObjs.TCountdownEvent.Signal] (HTTP: // docwiki.embarcadero.com/Libraries/en/System.SyncObjs.TCountdownEvent.Signal) для примера декремента потокобезопасности. –

ответ

5

Это не поточно-безопасный.

  • Тема 1 читает FCount = 1, оценивает условие на True.
  • Тема 2 читает FCount = 1, оценивает условие на True.
  • резьба 1 декременты FCount до 0
  • Темы 2 декрементирует FCount -1

Тем не менее, я полагаю, код специально предназначен для предотвращения снижения FCount ниже нуля.

Вы можете рассмотреть следующие вместо:

if InterlockedDecrement(FCount) < 0 then 
    InterlockedIncrement(FCount); 

Таким образом, один из двух параллельных потоков позволит уменьшить значение -1, а затем «исправить свою ошибку».
Однако он имеет побочный эффект, который может быть FCount временно < 0.

+0

Я вижу, код не является потокобезопасным. К сожалению, код, который вы предлагаете, я смутно подозреваю, что после вызова InterlockedDecrement другой поток может либо прочитать, либо изменить значение FCount до того, как будет назначено правильное значение. – Rimfire

+4

Нет. Это не так. Проблема в том, что нет никакой синхронизации при чтении в 'if'. –

+0

Так что я должен защищать чтение и увеличение с помощью критического раздела? – Rimfire

5

Код не является потоковым. Существует гонка по чтению FCount в заявлении if.

Поскольку я не знаю, что ваш код предназначен для достижения, то чем больше цель, я не буду предлагать решение.

1

Это не безопасный поток, как указывали другие. Если вы хотите, чтобы убедиться, что код уменьшает значение FCount, если оно больше 0, то вы могли бы использовать что-то вроде этого, не захватывая:

procedure TMyObject.Wait; 
var 
    count: Integer; 
    countPlus1: Integer; 
begin 
    repeat 
    count := FCount; 
    if (count > 0) then 
    begin 
     countPlus1 := count; 
     Dec(count); 
    end; 
    until (count <= 0) or (InterlockedCompareExchange(FCount, count, countPlus1) = countPlus1); 
    .. 
end; 

 Смежные вопросы

  • Нет связанных вопросов^_^