2013-11-15 2 views
1

Я хотел бы использовать свой собственный класс с несколькими свойствами. Я могу использовать read и write, чтобы настроить, как и какую (например) частную переменную писать или читать.Являются ли свойства класса потокобезопасными в delphi?

Примером может быть целым (MyInteger) в этом классе:

type 
    TMyClass = class 
    private 
    MyInteger : Integer; 
    function SomeFunction : Integer; 
    public 
    property TheInteger : Integer read SomeFunction write MyInteger; 
end; 

было бы безопасно, если (например) класс будет постоянно доступа (чтение) MyInteger, а другой поток обращается к TheInteger (запись) из другой поток текущего экземпляра?

Надеется, что вы, ребята, знаете, что я имею в виду ... В принципе, я не знаю, если это безопасно в общем, если несколько потоков обращается к вару в памяти, в то же время ... (без критических секций)

EDIT :

будет ли также разница между этим классом:

type 
    TMyClass = class 
    private 
    MyInteger : Integer; 
    function SomeFunction : Integer; 
    public 
    property TheInteger : Integer read MyInteger write MyInteger; 
end; 

и это:

type 
    TMyClass = class 
    private 
    function SomeFunction : Integer; 
    public 
    MyInteger : Integer; 
end; 

?

+2

http://stackoverflow.com/a/17706947/62576 –

+3

Нет, это не поточно-, вам нужно защитить общие ресурсы от одновременного доступа, будь то с критической секции или заблокированном API, что это ваш выбор. –

+0

@KenWhite Это не то, что я хотел знать. Я думал, используя команды 'read' и' write', delphi может автоматически позаботиться о состоянии гонки с его собственными критическими разделами. –

ответ

3

Место, где расположена переменная, не подразумевает никакой безопасности потоков. Это две совершенно разные концепции.

Что делает переменную нить безопасной или нет, так это то, как вы управляете ею.

Например, это будет поточно, потому что единственный способ манипулировать FMyInt через один из трех методов, которые все реализуются в поточно-образом:

type 
    TMyClass = class 
    strict private 
    FMyInt : Integer; 
    public 
    procedure IncrementValue; 
    function QueryValue : Integer; 
    function SubtractValue(aWhat : Integer) : Integer; 
    end; 

procedure TMyClass.IncrementValue; 
begin 
    InterlockedIncrement(FMyInt); 
end; 

function TMyClass.QueryValue : Integer; 
begin 
    result := InterlockedExchangeAdd(FMyInt, 0); 
end; 

function TMyClass.SubtractValue(aWhat : Integer) : Integer; 
begin 
    result := InterlockedExchangeAdd(FMyInt, -aWhat); 
end; 

И так бы это , но менее эффективны. Блокировка не подходит для каждого, так что это действительно зависит от варианта использования, какой метод следует использовать.

type 
    TMyClass = class 
    strict private 
    FMyInt : Integer; 
    FLock : TCriticalSection; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    procedure IncrementValue; 
    function QueryValue : Integer; 
    function SubtractValue(aWhat : Integer) : Integer; 
    end; 

constructor TMyClass.Create; 
begin 
    inherited; 
    FLock := TCriticalSection.Create; 
end; 

destructor TMyClass.Destroy; 
begin 
    FreeAndNil(FLock); 
    inherited; 
end; 

procedure TMyClass.IncrementValue; 
begin 
    FLock.Enter; 
    try 
    Inc(FMyInt); 
    finally 
    FLock.Leave; 
    end; 
end; 

function TMyClass.QueryValue : Integer; 
begin 
    FLock.Enter; 
    try 
    result := FMyInt; 
    finally 
    FLock.Leave; 
    end; 
end; 

function TMyClass.SubtractValue(aWhat : Integer) : Integer; 
begin 
    FLock.Enter; 
    try 
    Dec(FMyInt, aWhat); 
    result := FMyInt; 
    finally 
    FLock.Leave; 
    end; 
end; 

Обратите внимание, что одни и те же работы, если я ставлю значения в record и иметь кучу функций и процедур, делающих манипуляции. Место, где хранится/хранится переменная (ы), не имеет значения.

ПДО & Dont в

Никогда не смешивайте различные виды замков. Например, смешивание взаимосвязанных функций с TCriticalSection или смешивание TCriticalSection с TMutex или смешивание любых замков с полностью неохраняемым доступом. Это будет рецептом сбоя, потому что разные блокировки не знают друг друга.

Имейте в виду, что большинство механизмов блокировки - это только логические блокировки, которые на самом деле не мешают вам делать что-то безумное с вашими данными. Поэтому это хороший подход к инкапсулированию доступа к данным в максимально возможной степени для контроля.

+1

Этот ответ не имеет смысла. Какая семантическая разница между кодом блокировки и кодом с блокировками или блокированным доступом. Пожалуйста, скажите мне семантическую наблюдаемую разницу. Если только один поток пишет, зачем вы используете блокировку? Там нет разрывов. Любая раса может быть только доброкачественной. Пожалуйста, дайте мне пример режима сбоя из-за отсутствия блокировки для переменной типа Integer с модификацией одного потока. –

+1

Можем ли мы гарантировать выравнивание? –

+0

@WarrenP Да, мы можем. Мы просто должны избегать упаковки вещей. –

4

вы спросите, есть ли какая-то разница с точки зрения безопасности потока между:

type 
    TMyClass = class 
    private 
    MyInteger : Integer; 
    public 
    property TheInteger : Integer read MyInteger write MyInteger; 
end; 

и:

type 
    TMyClass = class 
    public 
    MyInteger : Integer; 
end; 

Там нет никакой разницы. Компилятор генерирует идентичный код для обоих вариантов. Компилятор вообще не вводит код синхронизации.

Фактически, ни в коем случае компилятор никогда не вставлял код синхронизации потоков. Некоторые функции библиотеки имеют синхронизацию потоков, например TInterfacedObject._AddRef и т. Д., Но сам компилятор никогда не пишет код синхронизации. Ответственность за безопасность потоков зависит всегда от вашего программиста.


Для более конкретного примера давайте рассмотрим конкретный код в вашем вопросе.

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

Ваш сценарий - это один поток записи и несколько прочитанных потоков. Вы не указываете дополнительные ограничения для заказа. Имея эти факты и ограничения, нет необходимости в каких-либо блокировках. Любые расы данных должны быть доброкачественными, а код без блокировки семантически неотличим от кода с использованием блокировок или блокированного доступа.

Когда вам нужно синхронизировать доступ?

  • Если у вас несколько потоков записи, вам необходимо синхронизировать доступ.
  • Если ваша переменная не выровнена или больше, чем указатель, вам необходимо выполнить синхронизацию.
+1

Я бы предложил внимательно прочитать вопрос еще раз. – JensG

+1

@JensG Oh. Я пропустил часть вопроса, где указано, что существует несколько потоков записи. Или что целочисленная переменная неверно выровнена? И даже если бы я это сделал, мои пункты были точными. –

+1

Nope. У вас еще две попытки. – JensG

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