Практическое использование потоков
Практическое использование потоков
Когда измененяются папки
Перевод А. И. Легалова
Англоязычный оригинал находится на сервере компании Reliable Software
Вы когда-либо задались вопросом: каким оразом Проводник (Explorer) узнает о том, что некоторое действие должно модифицировать его окно, потому что был добавлен или удален файл в текущей папке некоторым внешним приложением? Больше этому можно не удивляться, потому что использование нашего Активного Объекта позволяет делать то же самое и даже больше. Есть несколько простых вызовов API, с помощью которых Вы можете запросить у файловой системы, чтобы она избирательно сообщила Вам относительно изменений для файлов и папок. Как только Вы устанавливаете такую вахту, ваш поток может отправляться спать, ожидая прихода событий. Файловая система отреагирует на событие, как только она обнаружит вид изменения, за которым вы наблюдаете.
Загрузка исходных текстов приложения FolderWatcher (zip архив 11K).
Без дальнейшей суеты унаследуем FolderWatcher из ActiveObject. Зададим в качестве источника уведомления — событие, а в качестве приемника уведомления — дескриптор к окна, отвечающего на уведомление. Исходное событие установлено в конструкторе FolderWatcher. Важно также запустить удерживаемый поток в конце конструктора.
class FolderWatcher : public ActiveObject {
public: FolderWatcher(char const* folder, HWND hwnd) : _notifySource (folder), _hwndNotifySink (hwnd) {
strcpy(_folder, folder);
_thread.Resume();
}
~FolderWatcher() {
Kill();
}
private:
void InitThread() {}
void Loop();
void FlushThread() {}
FolderChangeEvent _notifySource;
HWND _hwndNotifySink;
char _folder[MAX_PATH];
};
Все действия в ActiveObject происходят внутри метода Loop. Здесь мы устанавливаем "бесконечный" цикл, в котором поток должен ожидать событие. Когда событие происходит, мы проверяем флажок _isDying (как обычно) и посылаем специальное сообщение WM_FOLDER_CHANGE окну, которое имеет дело с уведомлениями. Это — не предопределенное сообщение Windows. Оно специально определено нами для передачи уведомления о папке от одного потока другому.
Происходит следующее: удерживаемый поток делает другой вызов API, чтобы позволить файловой системе, узнать, что она нуждается в большем количестве уведомлений. Затем управление возвращается к ожидающему потоку, находящемуся в состоянии сна. Одновременно Windows получает наше сообщение WM_FOLDER_CHANGE из очереди сообщений и посылает его оконной процедуре принимающего окна. Подробности чуть позже.
UINT const WM_FOLDER_CHANGE = WM_USER;
void FolderWatcher::Loop() {
for (;;) {
// Wait for change notification
DWORD waitStatus = WaitForSingleObject(_notifySource, INFINITE);
if (WAIT_OBJECT_0 == waitStatus) {
// If folder changed
if (_isDying) return;
PostMessage(_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM)_folder);
// Continue change notification
if (!_notifySource.ContinueNotification()) {
// Error: Continuation failed
return;
}
} else {
// Error: Wait failed
return;
}
}
}
Рассмотрим, что происходит в оконной процедуре в ответ на наше специальное сообщение. Мы вызываем метод Контроллера OnFolderChange. Этот метод может делать все, что мы захотим. В Проводнике (Explorer) он регенерирует отображение содержимого папки, которую мы наблюдаем. В нашем примере он только вызывает простое окно сообщения. Обратите внимание, что мы передаем имя измененной папки как LPARAM. Совершенно неважно, как определить WPARAM и LPARAM, в сообщении, определяемом пользователем.
Между прочим, Наблюдатель Папки — только часть Контроллера.
case WM_FOLDER_CHANGE:
pCtrl->OnFolderChange(hwnd, (char const *)lParam);
return 0;
void Controller::OnFolderChange(HWND hwnd, char const * folder) {
MessageBox(hwnd, "Change Detected, "Folder Watcher", MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK);
}
class Controller {
public:
Controller(HWND hwnd, CREATESTRUCT * pCreate);
~Controller();
void OnFolderChange(HWND hwnd, char const *folder);
private:
FolderWatcher _folderWatcher;
};
Теперь, когда мы знаем, как иметь дело с уведомлением, давайте взглянем на их источники, События изменяющие файлы. Объект события создан файловой системой в ответ на FindFirstChangeNotification. Дескриптор этого события возвращен из вызова. Мы запоминаем этот дескриптор и используем его позже, чтобы или осуществить восстанавление или отказаться от нашего интереса к дальнейшим уведомлениям. Обратите внимание, что мы можем устанавливать наблююдение рекурсивно, то есть, наблюдать данную папку и все ее подпапки и подподпапки. Мы можем также выражать интерес к специфическим изменениям, передавая поразрядное ИЛИ для любой комбинации следующих флажков:
• FILE_NOTIFY_CHANGE_FILE_NAME (переименование, создание или удаление файла)
• FILE_NOTIFY_CHANGE_DIR_NAME (создание или удаление каталога (папки))
• FILE_NOTIFY_CHANGE_ATTRIBUTES
• FILE_NOTIFY_CHANGE_SIZE
• FILE_NOTIFY_CHANGE_LAST_WRITE (сохранение файла)
• FILE_NOTIFY_CHANGE_SECURITY
Для удобства мы определили несколько подклассов от FileChangeEvent, которые соответствуют к некоторым полезным комбинациям этих флажков. Один из них — FolderChangeEvent, который мы использовали в нашем FolderWatcher.
class FileChangeEvent {
public:
FileChangeEvent(char const *folder, BOOL recursive, DWORD notifyFlags) {
_handle = FindFirstChangeNotification(folder, recursive, notifyFlags);
if (INVALID_HANDLE_VALUE == _handle) throw WinException("Cannot create change notification handle");
}
~FileChangeEvent() {
if (INVALID_HANDLE_VALUE != _handle) FindCloseChangeNotification(_handle);
}
operator HANDLE() const { return _handle; }
BOOL ContinueNotification() {
return FindNextChangeNotification(_handle);
}
private:
HANDLE _handle;
};
class FolderChangeEvent : public FileChangeEvent {
public:
FolderChangeEvent(char const* folder) : FileChangeEvent(folder, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME) {}
};
class TreeChangeEvent : public FileChangeEvent {
public:
TreeChangeEvent(char const * root) : FileChangeEvent (root, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME) {}
};
Должно быть теперь просто обобщить этот пример, чтобы сделать некоторую действительно полезную работу в ваших программах. Не забудьте посмотреть API, который мы используем в этих обучающих программах, в интерактивной справке, которая идет с вашим компилятором.
Далее: Программирование OLE и использование COM без MFC.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Стеки потоков и допустимые количества потоков
Стеки потоков и допустимые количества потоков Следует сделать еще два предостережения. Во-первых, подумайте о размере стека, который по умолчанию составляет 1 Мбайт. В большинстве случаев этого будет вполне достаточно, но если существуют какие-либо сомнения на сей счет,
Практическое запрещение кэширования
Практическое запрещение кэширования Запретить кэширование можно и прямо из конфигурации Apache (подробная конфигурация для оптимальной производительности приводится в восьмой главе). Для этого нам нужны следующие строки:# Проверяем, что подключен mod_headers# Тогда выставляем
Практическое решение
Практическое решение Решение выглядит весьма тривиально: мы можем в общем CSS-файле объявить правила для любого устройства через @media. Например, все стили для принтера могут быть записаны в следующем виде:@media print {стилевые правила для принтера}в конце основного файла
26.3. Использование потоков в функции str_cli
26.3. Использование потоков в функции str_cli В качестве первого примера использования потоков мы перепишем нашу функцию str_cli. В листинге 16.6 была представлена версия этой функции, в которой использовалась функция fork. Напомним, что были также представлены и некоторые другие
26.4. Использование потоков в эхо-сервере TCP
26.4. Использование потоков в эхо-сервере TCP Теперь мы перепишем эхо-сервер TCP, приведенный в листинге 5.1, используя для каждого клиента по одному потоку вместо одного процесса. Кроме того, с помощью нашей функции tcp_listen мы сделаем эту версию не зависящей от протокола. В
Практическое черчение
Практическое черчение Для быстрого и качественного выполнения сложных чертежей недостаточно одного знания инструментальных средств, предоставляемых графическим редактором. Если вы прочли все написанное выше, то наверняка представляете, что КОМПАС-График дает
Практическое моделирование
Практическое моделирование Разработка трехмерной модели – сложный творческий процесс, который предполагает у проектировщика не только знание предмета проектирования и программных средств, но и наличие неординарного и гибкого мышления. Почему это творческий процесс?
Практическое определение объекта
Практическое определение объекта Вы можете заметить, что порой представить объект VBA в материально осязаемом виде не так-то просто. Но это и к лучшему - чем дальше вы уходите от материализации объектов, тем свободнее будете себя чувствовать при работе со всем диапазоном
2.4. Практическое задание. Натюрморт
2.4. Практическое задание. Натюрморт Изучая моделирование трехмерных объектов, мы стремимся создавать большие и сложные работы, но оказывается, что простыми средствами можно добиться вполне приемлемых результатов. Ключ к успеху не только в том, чтобы модель или сцена была
7.4. Практическое задание. Боулинг
7.4. Практическое задание. Боулинг Как вы можете догадаться из названия упражнения, мы будем говорить о боулинге, а точнее, о динамике твердых тел, использованной при моделировании такой сцены. Нам понадобится примитивный зал для боулинга, кегли и шар. Вы можете
1.2. Практическое применение графологии
1.2. Практическое применение графологии В настоящее время графология во многих странах мира эффективно применяется в нескольких направлениях. При отборе персонала делается графологический анализ автобиографии или заявления о приеме на работу. Используется графология и
10.2.6. Практическое использование Google
10.2.6. Практическое использование Google В этом разделе мы поговорим о практическом использовании Google, а именно поиске рефератов, дипломных и курсовых работ, поиске картинок и новостей.Поиск рефератов, дипломных, курсовых работВ Интернете очень много сайтов, содержащих уже
Практическое занятие
Практическое занятие Рассчитаем гороскоп ребенка, родившегося 4 августа 2006 года в 22:45 в Москве.Сначала надо выбрать систему домов. В главном меню выполните команду Конфигурация | Дома. В открывшемся окне Система Домов выберите Плацидус, как показано на рис. 4.17. Затем