Создание модального диалогового окна фоновом потоке
От: Melamed Россия  
Дата: 25.05.20 12:17
Оценка:
Моя программа копирует файлы в фоновом потоке. При этом основное окно, создало модальное окно, отражающее ход копирования файлов. Но в случае, если в директории существует файл с таким же именем, то хотелось бы запросить, что с ним делать: переписать, отменить копирования данного файла. Я создаю модальное диалоговое окно в фоновом потоке с помощью функции DialogBoxParam. Окно создается, и работает нормально, но можно переключится между модальными диалоговыми окнами, созданными в основном и в фоновом потоке, что не желательно. Надо еще учесть, что от выбора пользователя зависит, что будет делать с этим файлом фоновый поток.
Re: Создание модального диалогового окна фоновом потоке
От: qaz77  
Дата: 25.05.20 14:27
Оценка: +2
Здравствуйте, Melamed, Вы писали:
M> Я создаю модальное диалоговое окно в фоновом потоке с помощью функции DialogBoxParam. Окно создается, и работает нормально, но можно переключится между модальными диалоговыми окнами, созданными в основном и в фоновом потоке, что не желательно.

Чтобы нельзя было переключаться, надо DialogBoxParam указать hwnd основного окна в качестве родителя. Родитель модального окна может быть даже в другом процессе.
Тут все равно будет два цикла обработки сообщений: в основном UI потоке и в модальном цикле в фоновом потоке, что на мой взгляд избыточно.

Лучшая реализация — послать SendMessage из фонового потока основному окну.
Это заблокирует фоновый поток до возврата из SendMessage, в вся работа с UI будет в основном потоке.
Re[2]: Создание модального диалогового окна фоновом потоке
От: Melamed Россия  
Дата: 27.05.20 21:49
Оценка:
Здравствуйте, qaz77, Вы писали:

Q>Здравствуйте, Melamed, Вы писали:

M>> Я создаю модальное диалоговое окно в фоновом потоке с помощью функции DialogBoxParam. Окно создается, и работает нормально, но можно переключится между модальными диалоговыми окнами, созданными в основном и в фоновом потоке, что не желательно.

Q>Чтобы нельзя было переключаться, надо DialogBoxParam указать hwnd основного окна в качестве родителя. Родитель модального окна может быть даже в другом процессе.

Q>Тут все равно будет два цикла обработки сообщений: в основном UI потоке и в модальном цикле в фоновом потоке, что на мой взгляд избыточно.

Q>Лучшая реализация — послать SendMessage из фонового потока основному окну.

Q>Это заблокирует фоновый поток до возврата из SendMessage, в вся работа с UI будет в основном потоке.

Данный способ имеет один существенный недостаток. Если есть в директории первый из копируемых файлов, то сообщение, посланное из фонового потока, диалоговым окном в основном потоке не принимается. Поэтому пришлось отказаться от применения функции SendMessage в фоновом потоке. а создавать диалоговое окно в фоновом потоке и просто указать в качестве родительского окна диалоговое окно, в котором отражается ход процесса копирования.
Re[3]: Создание модального диалогового окна фоновом потоке
От: qaz77  
Дата: 02.06.20 08:26
Оценка: 1 (1) +1
Здравствуйте, Melamed, Вы писали:

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


Неверно. Что-то не так делаешь.

Если в основном потоке крутится модальный или основной цикл обработки сообщений, то все сообщения для окон этого потока туда попадут, а также сообщения, посланные самому потоку (PostThreadMessage). При использовании SendMessage между потоками Windows автоматом обеспечивает синхронизацию и ожидание возврата на вызывающей стороне в блокирующем режиме (как WaitForSingleObject). Тут главное, чтобы вызываемый поток из обработчика сообщения не делал SendMessage обратно вызывающему, иначе случится банальный дедлок.

Чем плоха идея создавать окно в рабочем/фоновом потоке. Поток, в котором есть окна должен прокачивать сообщения, чтобы окна корректно перерисовывались как минимум.
Если поток долго не обрабатывает сообщения, то система создает суррогатные окна с заголовком "Не отвечает" вместо всех его окон верхнего уровня.

Так что делает фоновый поток: крутится в цикле обработки сообщений или выполняет свою работу (копирует файлы, в твоем случае)?

Самый распространенный костыль — это вставка в рабочий поток while(PeekMessage(...)) { ... } в некоторые точки между полезным действием.
Недостатки его:
1. полезные действия могут быть длительные и неделимые, опять приходим к тому, что окно не отвечает;
2. рабочий поток иногда выбирает и диспетчеризирует сообщения вместо выполнения полезной работы, что снижает эффективность использования ядра CPU.

В своей практике для решения задачи с показом прогресса и рабочим потоком я пришел к следующему решению.
Делается структура с информацией о ходе полезной работы ProgessInfo, наполнение которой может зависеть от характера работы.
Структура защищается критической секцией. Обеспечивается доступ к ней под критической секцией из основного и рабочего потока.
Рабочий поток в своих контрольных точках кладет в структуру текущую информацию (FilesCopied=42).
Основной поток после старта рабочего просто показывает модальный диалог прогресса.
Диалог прогресса создает таймер, например на 0.5 секунды. По таймеру читаем структуры ProgressInfo и обновляем текст и прогресс бар.
Когда рабочий поток закончил полезное действие, он делает SendMessage окну прогресса, чтобы оно немедленно закрылось (не ждало следующего срабатывания таймера).

Как вариант можно в основном потоке создавать модальное окно прогресса не сразу, а с некоторой задержкой.
Это позволит выполнять короткие действия без создания модального окна, не будет раздражающего пользователя мелькания...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.