Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как сделать аналог SendMessage, именно для потока, а не для окна. 
V
    Опции темы
Dreamer_0x01
Дата 19.1.2006, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



У меня есть поток, производный от CWinThread.
Мне нужно сделать что-то аналогичное PostThreadMessage(), но только чтобы такой вызов работал по типу функции SendMessage, то есть до обработки сообщения переход к следующей за вызовом этой функции команде не осуществлялся.


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Fin
Дата 19.1.2006, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дракон->Спать();
**


Профиль
Группа: Участник
Сообщений: 687
Регистрация: 4.1.2006

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



Можно объединить очереди потоков, и работать уже как обычно в одной очереди. Описано в книге Рихтера.


--------------------
Пролетал мимо.
PM MAIL   Вверх
Dreamer_0x01
Дата 19.1.2006, 17:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



у меня нет книги Рихтера. Можно пример?


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Fin
Дата 19.1.2006, 23:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дракон->Спать();
**


Профиль
Группа: Участник
Сообщений: 687
Регистрация: 4.1.2006

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



Вот цитата из Рихтера по твоему вопросу.
Цитата
]
Теперь рассмотрим вторую функцию, предназначенную для отправки межпоточ ныхсообщений:

BOOL SendMessageCallhack( HWND hwnd, UINT uHsg, WPARAM лРагат, LPARAM lParam, SENDASYNCPROC pfnResultCallBack, ULONG_PTR dwOata);

И вновь первые четыре параметра идентичны параметрам функции SendMessage При вызове Вашим потоком SendMessageCallback отправляет сообщение в очередь синхронных сообщений потока-приемника и тут же возвращает управление вызыва ющему (т e Вашему) потоку Закончив обработку сообщения, поток-приемник асин хронно отправляет свое сообщение в очередь ответных сообщений Вашего потока. Позже система уведомит Ваш поток об этом, вызвав написанную Вами функцию; у нее должен быть следующий прототип,

VOID CALLBACK ResultCallBack( HWND hwnd. UINT uMsg, ULONG_PIR dwData, LRESULT lResult);

Адрес этой функции обратного вызова передается SendMessageCallback в параметре pfnResultCallBack А при вызове ResultCallBack в первых двух параметрах передаются описатель окна, закончившего обработкусообщения, и код (значение) самого сооб щения. Параметр dwData функции ResultCallBack всегда получает значение, передан ное SendMessageCallback в одноименном параметре. (Система просто берет то, что указано там, и передает Вашей функции ResultCallBack) Последний параметр функ ции ResultCallBack сообщает результат обработки сообщения, полученный от окон ной процедуры

Поскольку SendMessageCallback, передавая сообщение другому потоку, немедлен но возвращает управление, ResultCallBack вызывается после обработки сообщения потоком-приемником не сразу, а с задержкой. Сначала поток-приемник асинхронно ставит сообщение в очередь ответных сообщений потока-отправителя Затем при первом же вызове потоком-отправителем любой из функций GetMessage, PeekMessage, WaitMessage или одной из Send-функций сообщение извлекается из очереди ответных сообщений, и лишь потом вызывается Ваша функция ResultCallback.


Цитата

Вы можете заставить два и более потока совместно использовать одну и ту же очередь виртуального ввода и переменные локального состояния ввода с помощью функции AttachTbreadInput:

BOOL AttachThreadInput( DWORD idAttach, DWORD idAttachTo, BOOL fAttach);

Параметр idAttach задаст идентификатор потока, чьи переменные локального со стояния ввода и очередь виртуального ввода Вам больше не нужны, а паряметр idAtta chedTo — идентификатор потока, чьи переменные локального состояния ввода и вир туальная очередь ввода должны совместно использоваться потоками И, наконец, па раметр fAttach должен быть или TRUE, чтобы инициировать совместное использова ние одной очереди, или FALSE — тогда каждый поток будет вновь использовать свои переменные состояния ввода и очередь А чтобы одну очередь (и переменные состо яния ввода) разделяли более двух потоков, вызовите АttасЬТhrеаdInput соответствую щее число раз.


Рихтер не рекомендует связывать очереди. Так как провис одного потока, может отразится на работе второго.


--------------------
Пролетал мимо.
PM MAIL   Вверх
Earnest
Дата 20.1.2006, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Функция SendMessageCallback работает не так, как нужно Dreamer'у: она возвращает управление сразу же, а не ждет, пока сообщение обработают.
А вот функция SendMessage как раз ждет.
Dreamer_0x01, ты ведь знаешь, что даже PostThreadMessage ты можешь вызвать только для потока у которого есть очередь сообщений (т.е. интерфейсного)? А значит и окно есть. Ну и отправляй синхронные сообщения главному окну этого потока. Нарисуй метод MyThread::SendThreadMessage, чтобы инкапсулировать это. И поаккуратнее с SendMessage - можешь легко получить Deadlock.
Если же поток не интерфейсный, то никаких сообщений, только события и прочие объекты синхронизации.


--------------------
...
PM   Вверх
Dreamer_0x01
Дата 20.1.2006, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



Цитата(Earnest @ 20.1.2006, 12:52 Найти цитируемый пост)

ты ведь знаешь, что даже PostThreadMessage ты можешь вызвать только для потока у которого есть очередь сообщений (т.е. интерфейсного)?

Ага, интерфейсный, я специально ради такого механизма и замутил это дело, хочу попробовать,мне кажется, будет удобно весьма.
Цитата(Earnest @ 20.1.2006, 12:52 Найти цитируемый пост)

Ну и отправляй синхронные сообщения главному окну этого потока

А где его взять, главное окно-то?
И как потом это главное окно завтавить пересылать сообщения этому потоку? ручную?
Или есть какой-то механизм, позволяющий "высасывать" сообщения из главного окна?



--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 20.1.2006, 14:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(Dreamer_0x01 @ 20.1.2006, 13:14 Найти цитируемый пост)

А где его взять, главное окно-то?

Что значит, где взять? Пусть будет первое попавшеся окно потока. Ну или создай, в конце концов - тогда уж только для приема сообщения потока.
Цитата(Dreamer_0x01 @ 20.1.2006, 13:14 Найти цитируемый пост)

Или есть какой-то механизм, позволяющий "высасывать" сообщения из главного окна?

Ага, называется "цикл обработки сообщений" (GetMessage - DispatchMessage). smile

Цитата(Dreamer_0x01 @ 20.1.2006, 13:14 Найти цитируемый пост)

И как потом это главное окно завтавить пересылать сообщения этому потоку? ручную?

Так, стоп. Что значит "пересылать"? Сообщения, посланные окну, всегда обрабтываются в потоке этого окна.






--------------------
...
PM   Вверх
Dreamer_0x01
Дата 20.1.2006, 15:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



Цитата(Earnest @ 20.1.2006, 14:15 Найти цитируемый пост)

Что значит, где взять? Пусть будет первое попавшеся окно потока.

Цитата(Earnest @ 20.1.2006, 14:15 Найти цитируемый пост)

Так, стоп. Что значит "пересылать"? Сообщения, посланные окну, всегда обрабтываются в потоке этого окна.


Я уже ничего не понимаю и запутался.
Поток я создаю так:
Код

class MyThread : public CWinThread
{
//..........
};

class CRegeDVI_03App : public CWinApp
{
//..........
private:
    MyThread * WorkThread;
};

BOOL CRegeDVI_03App::InitInstance()
{
//.........
    CRuntimeClass* prt = RUNTIME_CLASS( MyThread );
    ASSERT( lstrcmp( prt->m_lpszClassName, "MyThread" )  == 0 );
    this->WorkThread=(MyThread*)AfxBeginThread(prt);
//окон никаких на данном этапе я ведь еще не создаю
    return FALSE;
}


B где мне взять здесь это самое окно?

Цитата(Earnest @ 20.1.2006, 14:15 Найти цитируемый пост)

Цитата(Dreamer_0x01 @ 20.1.2006, 13:14 )

Или есть какой-то механизм, позволяющий "высасывать" сообщения из главного окна?


Ага, называется "цикл обработки сообщений" (GetMessage - DispatchMessage).


А куда мне вставить эту конструкцию?
Надо переопределить метод Run(), или какой-то другой метод?




--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Fin
Дата 20.1.2006, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дракон->Спать();
**


Профиль
Группа: Участник
Сообщений: 687
Регистрация: 4.1.2006

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



PS Прошу прошение за орфографию. Такова оцифровка электронного варианта.
Для прояснения ситуации, вот еше несколько цитат:
Цитата

Очередь сообщений потока
Как я уже говорил, одна из главных целей Windows — предоставить всем приложени ям отказоустойчивую среду. Для этого любой поток должен выполняться в такой сре де, где он может считать себя единственным. Точнее, у каждого потока должны быть очереди сообщений, полностью независимые от других потоков. Кроме того, для каж дого потока нужно смоделировать среду, позволяющую ему самостоятельно управлять фокусом ввода с клавиатуры, активизировать окна, захватывать мышь и т. д

Создавая какой-либо поток, система предполагает, что он не будет иметь отноше ния к поддержке пользовательского интерфейса. Это позволяет уменьшшь объем выделяемых ему системных ресурсов. Но, как только поток обратится к той или иной GUI-функции (например, для проверки очереди сообщений или создания окна), сис тема автоматически выделит сму дополнительные ресурсы, необходимые для выпол нения задач, связанных с пользовательским интерфейсом А ссли конкретнее, то сис тема создает структуру THREADINFO и сопоставляет ее с этим потоком

Элементы этой структуры используются, чтобы обмануть поток — заставить его считать, будто он выполняется в среде, принадлежащей только ему. THREADINFO — это внутренняя (недокументированная) структура, идентифицирующая очередь асин хронных сообщений потока (posted-message queue), очередь синхронных сообщений потока (sent-message queue), очередь ответных сообщений (reply-message queue), оче редь виртуального ввода (virtualized input queue) и флаги пробуждения (wakc flags), она также включает ряд других переменных-членов, характеризующих локальное состояние ввода для данного потока


Из этой цитаты следует, что любой поток может иметь очередь сообшений. И эта очередь создается автоматически. Без лишних усилий со стороны программиста.
Цитата

Во-первых, переданное сообщение присоединяется к очереди сообщений пото ка-приемника, в результате чего для зтого потока устанавливается флаг QSSEND MESSAGE. Во-вторых, если поток-приемник в данный момент выполняет какой-то код и не ожидает сообщений (через вызов GetMessage, PeekMessage или WaitMessage), пе реданное сообщение обработать не удастся — система нс прсрвст работу потока для немедленной обработки сообщения. Но когда поток-приемпик ждет сообщений, си стема сначала проверяет, установлен ли флаг пробуждения QS_SENDMESSAGE, и, если да, просматривает очередь синхронных сообщений, отыскивая первое из них. В оче реди может находиться более одного сообщения Скажем, несколько потоков одно временно послали сообщение одному и тому же окну. Тогда система просто ставит эти сообщения в очередь синхронных сообщений потока.

Итак, когда поток ждет сообщений, система извлекает ил очереди синхронных сообщений первое и вызывает для ею обработки нужную оконную процедуру Если таких сообщений больше нет, флаг QS_SENDMESSAGE сбрасывается. Пока поток-при емник обрабатывает сообщение, поток, отправивший сообщение через SendMessage, простаивает, ожидая появления сообщения в очереди ответных сообщений По окон чании обработки значение, возвращенное оконной процедурой, передается асинх ронно в очередь ответных сообщений потока-отправителя Теперь он пробудится и извлечет упомянутое значение из ответного сообщения. Именно это значение и бу дет результатом вызова SendMessage C этого момента поток-отправитель возобнов ляет работу в обычном режиме

Ожидая возврата управления функцией SendMessage, поток в основном простаи вает. Но кое-чем он может заняться, если другой поток посылает сообщение окну, созданному первым (ожидающим) потоком, система тут же обрабатывает это сооб щение, не дожидаясь, когда поток вызовет GetMessage, PeekMessage или WaitMessage

Поскольку Windows обрабатывает межпоточные сообщения описанным выше образом, Ваш поток может зависнуть Допустим, в потоке, обрабатывающем синхрон ное сообщение, имеется "жучок", из-за которого поток входит в бесконечный цикл Что же произойдет с потоком, вызвавшим SendMessage? Возобновится ли когда-нибудь его выполнение? Значит ли это, что ошибка в одном приложении «подвесит» другое? Ответ — да!

Это верно даже в том случае, если оба потока принадлежит одному процессу


Это сообщение отредактировал(а) Fin - 20.1.2006, 16:36


--------------------
Пролетал мимо.
PM MAIL   Вверх
Dreamer_0x01
Дата 20.1.2006, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



Fin
Вс это конечно хорошо, но у меня на данном этапе нет окон, а SendMessage требует дескриптер окна, где же его взять?


--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Fin
Дата 20.1.2006, 17:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дракон->Спать();
**


Профиль
Группа: Участник
Сообщений: 687
Регистрация: 4.1.2006

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



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


--------------------
Пролетал мимо.
PM MAIL   Вверх
Dreamer_0x01
Дата 20.1.2006, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



Цитата(Fin @ 20.1.2006, 17:13 Найти цитируемый пост)

Для чего тебе нужно посылать сообшение потоку с подтверждением о исполнении?

Для синхронизации.

Цитата(Fin @ 20.1.2006, 17:13 Найти цитируемый пост)

Если изменять параметры работы потока, то это можно сделать другими путями. Например тот же объект ядра Event.

В предыдущей версии было так и сделано, у меня был рабочий поток, в которую передавался указатель на структуру, содержащую в себе критическую секцию, я по ней и синхронизировался.
А главному окну уже слал SendMessage, в котором отчитывался о проделанных действиях.
Но получилось так, что большую часть времени у меня поток простаивает, а когда пользователь совершает какие-то действия в главном окне,поток должен был выполнить массу действий и ответить.
Поэтому рабочий поток содержал в себе цикл, в котором все время опршивалось состояни нескольких переменных и в зависимости от них выполнялись какие-то действия. Состояния этих переменных, как и положено, обновлялись с заходом в критическую секцию. Я подумал, что вся эта фигня стала похожа на обыкновенный цикл обработки сообщений. Вот я и подумал, а не попробовать ли действительно воспользоваться для этой цели интерфейсным потоком и уже готовым циклом обработки сообщений.




--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Earnest
Дата 20.1.2006, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Из MSDN:
Functions to Override When Creating a User-Interface Thread

ExitInstance Perform cleanup when thread terminates. Usually overridden.
InitInstance Perform thread instance initialization. Must be overridden.
OnIdle Perform thread-specific idle-time processing. Not usually overridden.
PreTranslateMessage Filter messages before they are dispatched to TranslateMessage and DispatchMessage. Not usually overridden.

ProcessWndProcException Intercept unhandled exceptions thrown by the thread's message and command handlers. Not usually overridden.
Run Controlling function for the thread. Contains the message pump. Rarely overridden.

Т.е. можно переопределить и Run, но лучше PreTranslateMessage.

НО: как я понимаю, никаких окон в этом потоке ты создавать не предполагал. Если все же соберешься создать - то в InitInstance. Однако, как-то это криво - создать никому не нужное окно, только чтобы добиться синхронной передачи сообщений.
Я бы попробовала обеспечить синхронизацию сама: пишем функцию SendThreadMessage, в которой вызываем PostThreadMessage, и потом ждем специально созданного события. Естественно, еще потребуется какой-нибудь флаг, чтобы MyThread при обработке сообщения знал, что нужно сигналить событие. SetEvent я бы поставила в переопределенной PumpMessage (посмотри родной код Run).


--------------------
...
PM   Вверх
Dreamer_0x01
Дата 20.1.2006, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Терминатор
**


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

Репутация: 9
Всего: 12



Цитата(Earnest @ 20.1.2006, 17:26 Найти цитируемый пост)

Однако, как-то это криво - создать никому не нужное окно, только чтобы добиться синхронной передачи сообщений.

Слава богу, меня хоть кто-то понял =)
Цитата(Earnest @ 20.1.2006, 17:26 Найти цитируемый пост)

Я бы попробовала обеспечить синхронизацию сама: пишем функцию SendThreadMessage, в которой вызываем PostThreadMessage, и потом ждем специально созданного события.

Я вот тоже думал о подобном, но решил, что изобретаю велосипед.
Ладно,допустим, ишу такую функцию сам.

Что мне надо сделать в PreTranslateMessage?
Нужно проверять некий флаг, который будет выставлять моя функция SendThreadMessage(), и его сбрасывать, в случае, если он установлен, это ясно. Перед сбрасыванием мне нужно установить какое-то событие, это я тоже понял. А в самой функции SendThreadMessage() мне нужно после вызова PostThreadMessage ждать этого самого события.

Но вот что такое события MFC и с чем их едят, я не знаю. Можно пример использования?
Только просьба в МСДН не отсылать, там все по-английски, а от этого языка меня на рвоту тянет. ;)




--------------------
Нет ничего невозможного. Есть цели, и есть время и силы на их достижение.
PM ICQ   Вверх
Fin
Дата 20.1.2006, 17:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дракон->Спать();
**


Профиль
Группа: Участник
Сообщений: 687
Регистрация: 4.1.2006

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



Кто мешает в потоке сделать примерно такой код.
Код

while (!quit)
{
    WaitForSingleObject(hEv, o);            //Ждемс сброса флага занятости
    ..............................................            //Выполняем свои действия
    if (........)  ResetEvent(hEv);               //Если поток выполнил всю работу и нечего ему делать
                                                              //То можно повесить его в ожидание
}


Это сообщение отредактировал(а) Fin - 20.1.2006, 17:48


--------------------
Пролетал мимо.
PM MAIL   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




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


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

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