Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.09.07;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.005 c
2-1217279177
Jolik
2008-07-29 01:06
2008.09.07
Использовать TForm как TFrame


2-1217325989
ванъка
2008-07-29 14:06
2008.09.07
TLabel


3-1205301531
uniken1
2008-03-12 08:58
2008.09.07
Связи с использованием Query


2-1217413081
Alexey
2008-07-30 14:18
2008.09.07
Переименование файла


2-1217087498
fil-23
2008-07-26 19:51
2008.09.07
работа с компонентой ServerSocket и ClientSocket





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский