Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.09.07;
Скачать: CL | DM;

Вниз

Доступ к данным с разных потоков   Найти похожие ветки 

 
Ruzzz ©   (2008-07-25 03:33) [0]

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

Как безопасно считывать значения переменных, хранящих настройки, из разных потоков?

Я считаю: к любому параметру настроек доступ на чтение/запись только внутри CriticalSection, но в таком случае как это сделать удобней? Ведь настроек много. Может создавать хеш, и создать две функции: read/write(Name, Value), внутри которых и будет EnterCriticalSection...LeaveCriticalSection ? но это как-то не удобно. Может есть другие способы?

Если использовать класс для хранения настроек, то как используя EnterCriticalSection...LeaveCriticalSection, получать доступ read/write к его полям? что-то не пойму и все :( я так понимаю, использовать EnterCriticalSection...LeaveCriticalSection внутри методов такого класса это уже ошибка, т.к. ссылаться на сам обьект нужно внутри EnterCriticalSection...LeaveCriticalSection, или не так?


 
Loginov Dmitry ©   (2008-07-25 08:00) [1]

> Как безопасно считывать значения переменных, хранящих настройки,
> из разных потоков?


Считывание безопасно, если не выполняется одновременной записи.


> Я считаю: к любому параметру настроек доступ на чтение/запись
> только внутри CriticalSection, но в таком случае как это
> сделать удобней? Ведь настроек много. Может создавать хеш,
> и создать две функции: read/write(Name, Value), внутри
> которых и будет EnterCriticalSection...LeaveCriticalSection
> ? но это как-то не удобно. Может есть другие способы?


Разработай отдельный класс для доступа к настройкам приложения. Добавь в секцию public методы Lock() и Unlock(), это позволит обеспечить целостность обращения сразу к группе настроек. В каждом методе чтения/записи настроек используй следующий шаблон:

Lock;
try
 // обращение к настройкам
finally
 UnLock;
end;


 
Сергей М. ©   (2008-07-25 09:37) [2]


> использовать EnterCriticalSection...LeaveCriticalSection
> внутри методов такого класса это уже ошибка


Настолько же ошибка, насколько и использование любых других API-функций)


 
han_malign ©   (2008-07-25 10:46) [3]


> т.к. ссылаться на сам обьект нужно внутри EnterCriticalSection...LeaveCriticalSection, или не так?

- а что - порядок создания и время жизни тебе(разработчику) не известно?
Объект просто должен создаваться в основном потоке до запуска доп. потоков и разрушаться после остановки всех доп. потоков... Короче - иметь гарнтированное время жизни в области водимости.


 
Leonid Troyanovsky ©   (2008-07-25 11:01) [4]


> Ruzzz ©   (25.07.08 03:33)  

> Если использовать класс для хранения настроек, то как используя
> EnterCriticalSection...LeaveCriticalSection, получать доступ
> read/write к его полям? что-то не пойму и все :(

Доступ к полям надо осуществлять через геттер/сеттер,
т.е., потоки должны оперировать нужным свойством (property).
Ну, а EnterCriticalSection...LeaveCriticalSection обрамляет
код метода доступа (read & write).
И не забудь в конструкторе инициализировать КС.

--
Regards, LVT.


 
Тын-Дын ©   (2008-07-25 11:30) [5]


> Ruzzz ©   (25.07.08 03:33)  
> Как организовать доступ к данным с разных потоков в одном
> приложении?
>
> Как безопасно считывать значения переменных, хранящих настройки,
>  из разных потоков?
>
> Я считаю: к любому параметру настроек доступ на чтение/запись
> только внутри CriticalSection, но в таком случае как это
> сделать удобней? Ведь настроек много. Может создавать хеш,
>  и создать две функции: read/write(Name, Value), внутри
> которых и будет EnterCriticalSection...LeaveCriticalSection
> ? но это как-то не удобно. Может есть другие способы?
>
> Если использовать класс для хранения настроек, то как используя
> EnterCriticalSection...LeaveCriticalSection, получать доступ
> read/write к его полям? что-то не пойму и все :( я так понимаю,
>  использовать EnterCriticalSection...LeaveCriticalSection
> внутри методов такого класса это уже ошибка, т.к. ссылаться
> на сам обьект нужно внутри EnterCriticalSection...LeaveCriticalSection,
>  или не так?


Всё просто.

 TOptionClass=class
 private
   FCS: RTL_CRITICAL_SECTION;
   FOptionList: TStringList;
   function GetValue(Index: String): String;
   procedure SetValue(Index: String; const Value: String);
   procedure Lock;
   procedure Unlock;
 public
   constructor Create;
   destructor Destroy; override;
//    procedure Save(const FilePath: String);
//    procedure Load(const FilePath: String);
   property Value[Index: String]: String read GetValue write SetValue;
 end;

 TForm1 = class(TForm)
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

{ TOptionClass }

constructor TOptionClass.Create;
begin
 inherited;
 InitializeCriticalSection(FCS);
 FOptionList := TStringList.Create;
end;

destructor TOptionClass.Destroy;
begin
 FOptionList.Free;
 DeleteCriticalSection(FCS);
 inherited;
end;

function TOptionClass.GetValue(Index: String): String;
begin
 Lock;
 try
   Result := FOptionList.Values[Index];
 finally
   Unlock;
 end;
end;
procedure TOptionClass.SetValue(Index: String; const Value: String);
begin
 Lock;
 try
   FOptionList.Values[Index] := Value;
 finally
   Unlock;
 end;
end;

procedure TOptionClass.Lock;
begin
 EnterCriticalSection(FCS);
end;

procedure TOptionClass.Unlock;
begin
 LeaveCriticalSection(FCS);
end;


 
Ruzzz ©   (2008-07-25 17:14) [6]

Спасибо!!! Тын-Дын за код :) только вот решил TStringList не использовать, а делать set/get для каждого параметра отдельно, так как разные типы есть и не охота каждый раз из строки/в строку переводить, плюс добавлю проверку на правильность.

у меня еще вопросик, даже три :)

1) Как-то не понятно, получается что к отдельному потоку (к его адресному пространству) относится только, то что внутри метода Execute? то есть сам обьект-наследник TThread принадлежит главному потоку, тогда получается что поток в методе Execute не может безопасно изменять свои property?

2) Нормально ли будет использовать raise внутри EnterCriticalSection...LeaveCriticalSection, т.е. я пишу код записи, поэтому он внутри EnterCriticalSection...LeaveCriticalSection, но сперва я должен проверить, валидное ли новое значение, или просто проверять до входа в CriticalSection? Глупый наверное вопрос :) ну  уж извините, но наверное нужно будет читать API чтоб знать больше о разных CriticalSection

3) Loginov Dmitry вам спасибо за "Считывание безопасно, если не выполняется одновременной записи." - как-то аж яснее стало! но это точно? :) т.е. если одновременно несколько потоков считывают какую-то ячейку памяти, то это безопасно и если такой код не включать в CriticalSection - это считается нормальным тоном в программировании?


 
Тын-Дын ©   (2008-07-25 17:32) [7]


> Спасибо!!! Тын-Дын за код :) только вот решил TStringList
> не использовать, а делать set/get для каждого параметра
> отдельно, так как разные типы есть и не охота каждый раз
> из строки/в строку переводить, плюс добавлю проверку на
> правильность.


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


> 1) Как-то не понятно, получается что к отдельному потоку
> (к его адресному пространству) относится только, то что
> внутри метода Execute? то есть сам обьект-наследник TThread
> принадлежит главному потоку, тогда получается что поток
> в методе Execute не может безопасно изменять свои property?
>


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


> 2) Нормально ли будет использовать raise внутри EnterCriticalSection.
> ..LeaveCriticalSection, т.е. я пишу код записи, поэтому
> он внутри EnterCriticalSection...LeaveCriticalSection, но
> сперва я должен проверить, валидное ли новое значение, или
> просто проверять до входа в CriticalSection? Глупый наверное
> вопрос :) ну  уж извините, но наверное нужно будет читать
> API чтоб знать больше о разных CriticalSection


raise внутри потока использовать вполне нормально. Только исключение погаснет в недрах потока, повалив его,  если не применить дополнительных усилий для обработки исключения.


> 3) Loginov Dmitry вам спасибо за "Считывание безопасно,
> если не выполняется одновременной записи." - как-то аж яснее
> стало! но это точно? :) т.е. если одновременно несколько
> потоков считывают какую-то ячейку памяти, то это безопасно
> и если такой код не включать в CriticalSection - это считается
> нормальным тоном в программировании?


Это точно-)
но ведь возможно, что когда-либо потребуется повторное использование кода? В этом случае нужн обыть уверенным, что другие потоки не попытаются записывать в общие области памяти.


 
Loginov Dmitry ©   (2008-07-25 22:00) [8]

> Нормально ли будет использовать raise внутри EnterCriticalSection...Leave
> CriticalSection


EnterCriticalSection(...);
try

finally
 LeaveCriticalSection(...);
end;


в этом случае raise внутри блока try..finally вызывать вполне можно. LeaveCriticalSection(...) сработает, не сомневайся! :)


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


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


> это считается нормальным тоном в программировании?


обычно где есть чтение, там есть и запись. Если записи нет, то обычно - является нормальным тоном.


 
Loginov Dmitry ©   (2008-07-25 22:01) [9]

> к тем или иным объектам


 
Сергей М. ©   (2008-07-26 01:24) [10]


> к отдельному потоку (к его адресному пространству)


Нет у потока своего адресного пространства.
TLS (thread local storage) пока не в счет - оно тебя сейчас никак не парит.


> обьект-наследник TThread принадлежит главному потоку


Делфи-объект не может принадлежать никакому потоку.
Он просто есть или его нет, вне зависимости от того, кто его вызвал к жизни  кто явился его убийцей)


 
Сергей М. ©   (2008-07-26 01:26) [11]


> поток в методе Execute не может безопасно изменять свои
> property?


свои - на здоровье.



Страницы: 1 вся ветка

Текущий архив: 2008.09.07;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.015 c
1-1198217550
андр
2007-12-21 09:12
2008.09.07
DataSet to DLL


2-1216792046
TStas
2008-07-23 09:47
2008.09.07
Есть ли какой-то особенный класс исключений при записи в ReadOnly


2-1217069073
agress0r
2008-07-26 14:44
2008.09.07
Прога вылетает при подключениие dll в vista


2-1217419539
D7
2008-07-30 16:05
2008.09.07
FillChar


3-1205422412
Цукор5
2008-03-13 18:33
2008.09.07
OLE и FireBird