Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Потоки, файлы и ReadDirectoryChanges 
V
    Опции темы
dma
Дата 29.2.2008, 21:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 1.12.2006
Где: Belarus, Minsk

Репутация: нет
Всего: 1



Господа, помогите пожалуйста решить небольшой вопрос.
Заключается он в следующем:

Есть директория, в которую время от времени "падают" файлы. Состояние директории отслеживается при помощи ReadDirectoryChanges, которая по приходу нового файла говорит FILE_ACTION_ADDED. Есть так же несколько потоков - обработчиков файлов из этой директории. Вообще говоря каждый поток должен брать и обрабатывать файл своей маски, но иногда возникает ситуация, когда несколько потоков берут один и тот же файл (к примеру для них была установлена одинакавая маска, но это не суть). Так вот собственно сам FILE_ACTION_ADDED говорит о том, что файл только создался, а т.к. файл может быть большим, потоку нужно дождаться пока он полностью скопируется. Я реализовал это следующим образом:
Код

  repeat
    IsAllowed := true;
    try
      Sleep(10);
      if FileExists(FileName) then
        FFile := TFileStream.Create(FileName, fmOpenRead)
      else
      begin
        IsAllowed := False;
        break;
      end;
    except
      IsAllowed := False;
    end;
  until IsAllowed;

Таким образом получается, что когда файл скопируется, то какой-то из потоков его откроет на чтение, а остальные дальше будут ожидать освобождения файла, т.к. не смогут получить к нему доступ. Это хорошо smile Но после того, как поток произвёл некоторые действия с этим файлом, он должен его удалить. Чтобы его удалить, нада сначала закрыть FileStream. И вот здесь возникает проблема! Как гарантированно успеть удалить файл до того, как его успеет схватить другой поток после закрытия FileStream'a?

Буду благодарен за любую помощь. Или за предложение лучшего варианта решения проблемы smile

PM MAIL ICQ Skype GTalk   Вверх
bems
Дата 29.2.2008, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



Вместо TFileStream используй THandleStream. Файл открывай апишкой CreateFile с флагом FILE_FLAG_DELETE_ON_CLOSE и без FILE_SHARE_DELETE


--------------------
Обижено школьников: 8
PM MAIL   Вверх
dma
Дата 1.3.2008, 00:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 1.12.2006
Где: Belarus, Minsk

Репутация: нет
Всего: 1



ух ты! Спасибо! То что доктор прописал smile

Вкратце, получилось так (поправьте, если ошибся):

Код

var
  hsF: THandleStream;
  hwndF: HWND;
begin
  repeat
    Sleep(10);
    hwndF := INVALID_HANDLE_VALUE;
    if FileExists(FileName) then
      hwndF := CreateFile(pchar(FileName), GENERIC_READ, 0, nil,
       OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0)
    else
      break;
  until hwndF <> INVALID_HANDLE_VALUE;
  if hwndF <> INVALID_HANDLE_VALUE then
    hsF := THandleStream.Create(HWNDF);


Это сообщение отредактировал(а) dma - 1.3.2008, 13:19
PM MAIL ICQ Skype GTalk   Вверх
bems
Дата 1.3.2008, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



1)убери sleep(10)
2)дескриптор окна и объекта ядра это разные вещи, поэтому вместо hwndF: HWND сделай hFile:THandle, хотя формально это не ошибка
3)FileExists убери. Вместо него в условие until добавь проверку, что если CreateFile вернула INVALID_HANDLE_VALUE, то все равно можно закончить цикл если GetLastError вернула ERROR_FILE_NOT_FOUND или ERROR_PATH_NOT_FOUND. Так и от break избавишся
4)добавь секцию try-finally-end, чтобы убедиться что файл будет закрыт, даже если после его открытия возникло исключение
5) ну и если файл существует но занят, то долбиться в него нужно не бесконечно, а до какого-то предела - вдруг тот кто занял подвис, это же не значит, что вслед за ним должен подвиснуть и ты за компанию.


--------------------
Обижено школьников: 8
PM MAIL   Вверх
dma
Дата 1.3.2008, 23:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 1.12.2006
Где: Belarus, Minsk

Репутация: нет
Всего: 1



Снова спасибо за подсказки! smile

Есть пара вопросов:

если Sleep убрать, то этот цикл забьёт весь процесор... а если их ещё и несколько будет, дык вообще вёсла..

в try finally естественно всё это поместиться, я здесь просто рабочий кусок рассматривал smile

вобщем вышло что-то вроде этого:

Код

var
  hsF: THandleStream;
  hF: THandle;
begin
  repeat
    hF := CreateFile(PChar(FileName), GENERIC_READ, 0, nil,
     OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, 0);
  until ((Self.Terminated) or (hF <> INVALID_HANDLE_VALUE) or 
    ((GetLastError = ERROR_FILE_NOT_FOUND) or (GetLastError = ERROR_PATH_NOT_FOUND)));
  if hF <> INVALID_HANDLE_VALUE then
    hsF := THandleStream.Create(HF);


кстати, а корректно ли вызывать GetLastError два раза в проверке условия, или же лучше в цикле один раз вызвать и запомнить значение в переменную?


Это сообщение отредактировал(а) dma - 1.3.2008, 23:48
PM MAIL ICQ Skype GTalk   Вверх
dma
Дата 2.3.2008, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 1.12.2006
Где: Belarus, Minsk

Репутация: нет
Всего: 1



По поводу GetLastErrorCode почитал мануал, сам себе отвечу:  вроде как правильнее будет сохранить в переменную сразу после вызова CreateFile.
Цитата

You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data. That is because some functions call SetLastError(0) when they succeed, wiping out the error code set by the most recently failed function. 



PM MAIL ICQ Skype GTalk   Вверх
bems
Дата 2.3.2008, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



Цитата(dma @  1.3.2008,  23:45 Найти цитируемый пост)
если Sleep убрать, то этот цикл забьёт весь процесор... а если их ещё и несколько будет, дык вообще вёсла..
да, это так. Но со слипом, появляются неоправданые переключения контекста, что тоже плохо. Тут бы впасть в спячку до освобождения.
Файл занять чужим кодом или твоим?

Добавлено через 2 минуты и 45 секунд
как вариант сделать значительно более долгий слип - пару секунд


--------------------
Обижено школьников: 8
PM MAIL   Вверх
dma
Дата 2.3.2008, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 1.12.2006
Где: Belarus, Minsk

Репутация: нет
Всего: 1



Цитата(bems @  2.3.2008,  15:16 Найти цитируемый пост)
Файл занять чужим кодом или твоим?

 И чужим и моим. Когда поток ждёт, пока файл скопируется - он занят чужим кодом, потом, кода один из потоков захватывает файл, остальные ждут - то моим...
PM MAIL ICQ Skype GTalk   Вверх
bems
Дата 2.3.2008, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 21
Всего: 88



ну тогда проще длинный слип :(


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Riply
Дата 3.3.2008, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Комодератор
Сообщений: 572
Регистрация: 27.3.2007
Где: St. Petersburg

Репутация: 21
Всего: 32



Цитата(dma @  29.2.2008,  21:54 Найти цитируемый пост)
Есть так же несколько потоков - обработчиков файлов из этой директории. Вообще говоря каждый поток должен брать и обрабатывать файл своей маски


Мне казалось, что использование потоков для работы с файлами, 
расположенными на одном  диске, мякго говоря, - искуственное создание "тормозов".  smile 
Я ошибаюсь ? 

P.S.
 Имеется ввиду именно работа, а не ожидание чего-то.

PM MAIL   Вверх
Rennigth
Дата 3.3.2008, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 8
Всего: 76



Цитата(Riply @  3.3.2008,  12:13 Найти цитируемый пост)
Мне казалось, что использование потоков для работы с файлами, 
расположенными на одном  диске, мякго говоря, - искуственное создание "тормозов".   
Я ошибаюсь ? 

ну я думаю если реализация с несколькоми(разными) потоками сделана только из-за того что они должны выполнять разные действия с файлами, но паралельное использование нечастое/исключенное, то нормуль smile


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0816 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.