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


Автор: snakesoft 2.8.2013, 17:45
Всем привет!
Пишу утилиту для наблюдения за изменениями на подключенных съемных устройствах

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

Подозреваю, что проблема не в совсем корректном завершении потока в:

Код


procedure TForm1.WMDeviceChange(var Msg: TMessage);

...
  FileChanges[i].Terminate;
  FileChanges[i].WaitFor;
  FileChanges[i].Free;
...

end;


Если использовать

Код


procedure TForm1.WMDeviceChange(var Msg: TMessage);

...
  FileChanges[i]:=nil;
...

end;


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

Помогите пожалуйста решить проблему, исходник прилагается



Автор: Чучмек 2.8.2013, 18:17
Цитата(snakesoft @  2.8.2013,  17:45 Найти цитируемый пост)
  FileChanges[i].WaitFor;

Вот здесь и подвисает. Ждет пока поток отработает.
FreeOnTerminate

Добавлено через 3 минуты и 30 секунд
p.s. Возможно неправильно организованна остановка потока.

Автор: Чучмек 3.8.2013, 13:48
snakesoft, посмотрел твой код.
Твоя проблема в ReadDirectoryChangesW.
Эта функция,ожидающая изменений в каталоге, не возвращает управление после отключения флешки.
Отсюда и зависание   WaitFor, в основном потоке, ждет завершения  потока TFileThread, а тот в свою очередь висит на  ReadDirectoryChangesW.
Вариантов исправить это несколько.
1. Использовать ReadDirectoryChangesW в асинхронном режиме, тогда дополнительные потоки вообще не нужны.
2. Убивать поток через TerminateThread
3. либо ... еще незнаю, надо смотреть.

Автор: snakesoft 5.8.2013, 16:13
Спасибо, что помог!
Попробовал

Код

TerminateThread (FileChanges[i].Handle, 0);
FileChanges[i].Free();


Всё ок

Автор: MetalFan 6.8.2013, 14:31
Цитата(Чучмек @  3.8.2013,  13:48 Найти цитируемый пост)
2. Убивать поток через TerminateThread

Не очень хороший вариант, имхо.

Автор: Чучмек 6.8.2013, 14:49
Цитата(MetalFan @  6.8.2013,  14:31 Найти цитируемый пост)
Не очень хороший вариант, имхо. 

Но зато не требует серьезной переделки программы.
А вообще да, надо найти способ раздуплить ReadDirectoryChanges.
Асинхронный вариант тоже, по моему, не решает всего. Будет время - проверю.

Автор: Illusion Dolphin 6.8.2013, 19:38
Цитата

А вообще да, надо найти способ раздуплить ReadDirectoryChanges.

У меня работает оно так: отдельный поток,

Код

var
  FOverLapp: TOverlapped;

...
FCompletionPort := CreateIoCompletionPort(Handle, 0, CompletionKey, 0);
...
ReadDirectoryChanges(бла-бла,  @FOverLapp, nil)
...
GetQueuedCompletionStatus(CompletionPort,
    lpNumberOfBytesTransferred,
    lpCompletionKey, lpOverlapped, INFINITE);
...
//И когда надо отменить операцию:
PostQueuedCompletionStatus(CompletionPort, 0, 0, nil);
 
Вроде работает стабильно, без задержек. 

Автор: Чучмек 7.8.2013, 12:26
Illusion Dolphin да, это один из вариантов.
Я пытался присобачить порт завершения, но ...
Нормального русскоязычного описания функций не нашел, а в англицкой тарабарщине, от меня, смысл, порой, ускользает. 
Да и не уверен был что поможет, поэтому не старался.
Illusion Dolphin спасибо, подтолкнул в нужном направлении.

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