Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > помогите с потоками


Автор: РЮХ 3.6.2013, 08:20
В программе есть данные в виде объектов в TObjectList, нужно, например, по нажатию кнопки дописать в (большой) файл данные или изменить там данные. Что-бы было удобнее хочу перенести сохранение в отдельный поток. Нажал сохранить и добавить - он сохраняет, а пользователь дальше без тормозов работает. Про потоки почитал, простые примеры поизучал. Но как сделать реальную задачу пока не пойму. Т.к. файл с данными может быть один, то по идеи поток должет быть один для сохранения. Но сохранить может потребоваться и в тот момент когда уже идет сохранение (пред. не успел сохранится), надо как-то дождаться и дать команду сохранять следом другие данные. Помогите понять как это нужно организовать.

Автор: Akella 3.6.2013, 10:00
Читать до просветления
http://forum.vingrad.ru/forum/topic-60076.html

Автор: РЮХ 3.6.2013, 17:06
Как раз весь день мучал себя, но просветления нет. Много всего. К концу голова становится квадратной от теории.
Надо чтобы данные сохранялись в отдельных потоках, но потоки ждали предыдущие пока сохранят. Даже не придумаю как лучше подступится.

Автор: Чучмек 3.6.2013, 19:04
Цитата(РЮХ @  3.6.2013,  17:06 Найти цитируемый пост)
Надо чтобы данные сохранялись в отдельных потоках, но потоки ждали предыдущие пока сохранят. Даже не придумаю как лучше подступится. 

Один дополнительный поток для сохранения, и задания для него.

Автор: Poseidon 3.6.2013, 19:27
Цитата(РЮХ @  3.6.2013,  17:06 Найти цитируемый пост)
Много всего. К концу голова становится квадратной от теории.Надо чтобы данные сохранялись в отдельных потоках, но потоки ждали предыдущие пока сохранят.
Еще раз более глубоко и вдумчиво читай http://forum.vingrad.ru/forum/topic-60076/anchor-entry480380/0.html. Акцент на критические секции. 

Тебе надо: 
  • Cоздать класс - наследник TThread (один). Допустим TSaveFileThread
  • В этом классе описать метод сохранения данных в файл. При чем само сохранение засунуть в критическую секцию 
  • На каждое нажатие кнопки "Сохранить" создавать объект этого класса (грубо говоря, создавать поток и запускать его)
Цитата
Важно, что у критической секции в каждый момент времени может быть только один поток-владелец. Если поток пытается войти в критическую секцию, когда другой поток уже находится внутри нее, то он будет приостановлен, и возобновит свою работу, только когда другой поток выйдет из критической секции.


Еще можешь почитать про метод WaitFor. Специально для таких вот задач как у тебя "Надо чтобы данные сохранялись в отдельных потоках, но потоки ждали предыдущие пока сохранят." он и предусмотрен. WaitFor описан в http://forum.vingrad.ru/forum/topic-60076/anchor-entry480378/0.html

Автор: РЮХ 5.6.2013, 15:47
Не пойму.
В главном модуле завел переменную     
Sync: TRTLCriticalSection;
Создаю поток для сохранения.

Код

    InitializeCriticalSection(Sync);

    Thread := TSaveFileThread.Create(true);
    Thread.FreeOnTerminate := True;
    SetThreadPriority(Thread.Handle, THREAD_PRIORITY_BELOW_NORMAL);
    try
      Thread.D := Data;
    except
      //on EConvertError do FPrimeThread.StartNum := 2;
    end;
    Thread.Resume;


В потоке 
Код

procedure TSaveFileThread.Execute;
begin
      EnterCriticalSection(MainForm.Sync);
      if not (Terminated) then AddDataToFile(D, 'a.data');
      LeaveCriticalSection(MainForm.Sync);
end;


Данные сохраняются но через какое-то время или почему-то получаю ошибку
---------------------------
Debugger Exception Notification
---------------------------
Project My.exe raised exception class EFOpenError with message 'Cannot open file "D:\a.data". Процесс не может получить доступ к файлу, так как этот файл занят другим процессом'.
---------------------------
Break   Continue   Help   
---------------------------


Автор: Akella 5.6.2013, 16:05
Ошибка в 17ой строке.

Автор: Poseidon 5.6.2013, 16:36
Первый код - это OnClick кнопки "Сохранить"? Ты просто скопипастил код или все-таки попытался в нем разобраться? Прочти внимательно 
Цитата
Операции InitializeCriticalSection и DeleteCriticalSection можно рассматривать подобно созданию и освобождению объектов в куче. Обычно имеет смысл проводить действия по созданию и разрушению критических секций в одном потоке, причем в наиболее долгоживущем. 

В твоем случае самый долгоживущий поток - это основной поток программы.

Автор: РЮХ 5.6.2013, 17:28
Цитата(Akella @  5.6.2013,  16:05 Найти цитируемый пост)
Ошибка в 17ой строке.

?

Цитата(Poseidon @  5.6.2013,  16:36 Найти цитируемый пост)
Первый код - это OnClick кнопки "Сохранить"?

Можно считать так, на деле сложнее, пусть будет щелчок по кнопке или, например, событие таймера.


Цитата(Poseidon @  5.6.2013,  16:36 Найти цитируемый пост)
Ты просто скопипастил код или все-таки попытался в нем разобраться?

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

Цитата(Poseidon @  5.6.2013,  16:36 Найти цитируемый пост)
Обычно имеет смысл проводить действия по созданию и разрушению критических секций в одном потоке, причем в наиболее долгоживущем. В твоем случае самый долгоживущий поток - это основной поток программы.

Не пойму. Критическая сессия, как я понимаю, открытие и запись в файл. Мне ее наоборот нужно в отдельный поток вынести.

Автор: Poseidon 5.6.2013, 18:56
Цитата(РЮХ @  5.6.2013,  17:28 Найти цитируемый пост)
?

http://forum.vingrad.ru/act-Help/CODE-01/HID-17.html

Цитата(РЮХ @  5.6.2013,  17:28 Найти цитируемый пост)
Не пойму. Критическая сессия, как я понимаю, открытие и запись в файл. Мне ее наоборот нужно в отдельный поток вынести.
Правильно. Только вход в критическую секцию - это EnterCriticalSection и тут у тебя все правильно. А вот инициализация - InitializeCriticalSection - это совсем другое и, вероятнее всего, у тебя инициализируются разные секции.

Автор: РЮХ 5.6.2013, 22:03
Цитата(Poseidon @  5.6.2013,  18:56 Найти цитируемый пост)
А вот инициализация - InitializeCriticalSection - это совсем другое и, вероятнее всего, у тебя инициализируются разные секции.

Перенес в создание главной формы. Так вроде ок. Delete... ее обязательно делать?

Автор: Poseidon 5.6.2013, 22:28
Цитата(РЮХ @  5.6.2013,  22:03 Найти цитируемый пост)
Delete... ее обязательно делать?
Ну а как же? Освобождение ресурсов всегда обязательно делать.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)