![]() |
|
![]() ![]() ![]() |
|
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
У меня есть поток, производный от CWinThread.
Мне нужно сделать что-то аналогичное PostThreadMessage(), но только чтобы такой вызов работал по типу функции SendMessage, то есть до обработки сообщения переход к следующей за вызовом этой функции команде не осуществлялся. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Fin |
|
|||
![]() Дракон->Спать(); ![]() ![]() Профиль Группа: Участник Сообщений: 687 Регистрация: 4.1.2006 Репутация: 1 Всего: 10 |
Можно объединить очереди потоков, и работать уже как обычно в одной очереди. Описано в книге Рихтера.
-------------------- Пролетал мимо. |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
у меня нет книги Рихтера. Можно пример?
-------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Fin |
|
||||
![]() Дракон->Спать(); ![]() ![]() Профиль Группа: Участник Сообщений: 687 Регистрация: 4.1.2006 Репутация: 1 Всего: 10 |
Вот цитата из Рихтера по твоему вопросу.
Рихтер не рекомендует связывать очереди. Так как провис одного потока, может отразится на работе второго. -------------------- Пролетал мимо. |
||||
|
|||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Функция SendMessageCallback работает не так, как нужно Dreamer'у: она возвращает управление сразу же, а не ждет, пока сообщение обработают.
А вот функция SendMessage как раз ждет. Dreamer_0x01, ты ведь знаешь, что даже PostThreadMessage ты можешь вызвать только для потока у которого есть очередь сообщений (т.е. интерфейсного)? А значит и окно есть. Ну и отправляй синхронные сообщения главному окну этого потока. Нарисуй метод MyThread::SendThreadMessage, чтобы инкапсулировать это. И поаккуратнее с SendMessage - можешь легко получить Deadlock. Если же поток не интерфейсный, то никаких сообщений, только события и прочие объекты синхронизации. -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Ага, интерфейсный, я специально ради такого механизма и замутил это дело, хочу попробовать,мне кажется, будет удобно весьма. А где его взять, главное окно-то? И как потом это главное окно завтавить пересылать сообщения этому потоку? ручную? Или есть какой-то механизм, позволяющий "высасывать" сообщения из главного окна? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Что значит, где взять? Пусть будет первое попавшеся окно потока. Ну или создай, в конце концов - тогда уж только для приема сообщения потока.
Ага, называется "цикл обработки сообщений" (GetMessage - DispatchMessage). ![]()
Так, стоп. Что значит "пересылать"? Сообщения, посланные окну, всегда обрабтываются в потоке этого окна. -------------------- ... |
||||
|
|||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Я уже ничего не понимаю и запутался. Поток я создаю так:
B где мне взять здесь это самое окно? А куда мне вставить эту конструкцию? Надо переопределить метод Run(), или какой-то другой метод? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Fin |
|
||||
![]() Дракон->Спать(); ![]() ![]() Профиль Группа: Участник Сообщений: 687 Регистрация: 4.1.2006 Репутация: 1 Всего: 10 |
PS Прошу прошение за орфографию. Такова оцифровка электронного варианта.
Для прояснения ситуации, вот еше несколько цитат:
Из этой цитаты следует, что любой поток может иметь очередь сообшений. И эта очередь создается автоматически. Без лишних усилий со стороны программиста.
Это сообщение отредактировал(а) Fin - 20.1.2006, 16:36 -------------------- Пролетал мимо. |
||||
|
|||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Fin
Вс это конечно хорошо, но у меня на данном этапе нет окон, а SendMessage требует дескриптер окна, где же его взять? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Fin |
|
|||
![]() Дракон->Спать(); ![]() ![]() Профиль Группа: Участник Сообщений: 687 Регистрация: 4.1.2006 Репутация: 1 Всего: 10 |
Для чего тебе нужно посылать сообшение потоку с подтверждением о исполнении?
Если изменять параметры работы потока, то это можно сделать другими путями. Например тот же объект ядра Event. Опускаеш флаг, поток останавливаается. Ты своей функцией меняеш напрямую его параметры, затем обратно запускаеш поток. Все потоки в одном процессе находятся в одном адресном пространстве. Поэтому проблем с записью в память чужого потока, я лично не вижу. -------------------- Пролетал мимо. |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Для синхронизации.
В предыдущей версии было так и сделано, у меня был рабочий поток, в которую передавался указатель на структуру, содержащую в себе критическую секцию, я по ней и синхронизировался. А главному окну уже слал SendMessage, в котором отчитывался о проделанных действиях. Но получилось так, что большую часть времени у меня поток простаивает, а когда пользователь совершает какие-то действия в главном окне,поток должен был выполнить массу действий и ответить. Поэтому рабочий поток содержал в себе цикл, в котором все время опршивалось состояни нескольких переменных и в зависимости от них выполнялись какие-то действия. Состояния этих переменных, как и положено, обновлялись с заходом в критическую секцию. Я подумал, что вся эта фигня стала похожа на обыкновенный цикл обработки сообщений. Вот я и подумал, а не попробовать ли действительно воспользоваться для этой цели интерфейсным потоком и уже готовым циклом обработки сообщений. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 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). -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Слава богу, меня хоть кто-то понял =)
Я вот тоже думал о подобном, но решил, что изобретаю велосипед. Ладно,допустим, ишу такую функцию сам. Что мне надо сделать в PreTranslateMessage? Нужно проверять некий флаг, который будет выставлять моя функция SendThreadMessage(), и его сбрасывать, в случае, если он установлен, это ясно. Перед сбрасыванием мне нужно установить какое-то событие, это я тоже понял. А в самой функции SendThreadMessage() мне нужно после вызова PostThreadMessage ждать этого самого события. Но вот что такое события MFC и с чем их едят, я не знаю. Можно пример использования? Только просьба в МСДН не отсылать, там все по-английски, а от этого языка меня на рвоту тянет. ;) -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Fin |
|
|||
![]() Дракон->Спать(); ![]() ![]() Профиль Группа: Участник Сообщений: 687 Регистрация: 4.1.2006 Репутация: 1 Всего: 10 |
Кто мешает в потоке сделать примерно такой код.
Это сообщение отредактировал(а) Fin - 20.1.2006, 17:48 -------------------- Пролетал мимо. |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Ну хочется мне именно так попробовать сделать, и посмотреть, что получится, что ж тут поделать? ![]() -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Dreamer_0x01, извини, отвлекоась на семейные проблемы...
Если ты хочешь сделать так, как я написала, без окон, тебе надо перекрыть PumpMessage, а не PreTranslateMessage - потому что вторая вызывается ДО, а не после обработки сообщения. Если стандартная PumpMessage возвращает TRUE, вызывай SetEvent. Событие должно быть с автосбросом! Флаг нужно изменять атомарно! Не надо писать while (flag) в потоке! Ну ладно, английский ты не любишь, но код MFC кто мешает посмотреть?!!! -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
-------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Это означает, что нужно гарантировать, что никто не обратится к флагу, пока операция изменения не завершена - та самая межпоточная безопасность. Для защиты более сложных объектов приходится использовать как минимум critical section, но для int'ов есть специальные функции Interlocked***. Тебе подойдет InterlockedExchange.
-------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Earnest
Я делаю так(допустим, проверяю флаг FLAG1 внутри структуры MyStruct)
И в потоках делаю следующее:
Ты это имела в виду, или что-то принципиально другое? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Earnest |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Это, это, только зачем так сложно...
Если речь идет только о защите флага, то проще (короче и нагляднее) использовать функции Interlocked. Например:
Далее, в коде обработки собщений:
В этом фрагменте InterlockedExchange возвращает текущее значение флага и записывает туда 0 (мы ведь хотим, чтобы флаг, поставленный в SendThreadMessage, сработал единожды). И все это делается гарантированно атомарно. Соответственно, устанавливать флаг нужно вызовом InterlockedExchange((&pMyStruct->m_SyncFlag,1). Написала я этот код и подумала: здорово похоже на авто-событие. Там, может, событие и использовать? Еще одно. Т.е. примерно так:
PS MFC-обертки объектов ядра удобнее и нагляднее "родных" функций API. -------------------- ... |
||||||
|
|||||||
takedo |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 501 Регистрация: 1.6.2005 Репутация: нет Всего: 3 |
Dreamer_0x01
Во чего я подумал... Если у тебя в потоке нет окна, тогда вообще нет необходимости слать сообщения и вызывать страшные функции PreTranslateMessage и др. Создавай просто функцию bool func(); и ее вызывай. Это не будет отличатся от SendMessage, так как любое сообщение - суть вызов функции (в данном случае func()), ты ведь можешь её и сразу вызвать. А сообщения нужны лишь для того, чтобы не парится с синхронизацией, так как они обрабатываеются потоком, создавшим окно(посмотри ветку где куча народу спорила о синхронизации, я там пример из рихтера приводил, правда никто вроде бы не обратил внимания ![]() ![]() ![]() ![]() -------------------- я не гольфист - я хоккеист |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
takedo
Спасибо за поддержку, вот уж сюрприз ;)
Вот именно для этого.
Не-а, напрямую я ее не хочу вызывать. Ведь посылка сообщений напрямую функции-обработчики не вызывает, сначала сообщения ставятся в очередь, и лишь потом каким-то потоком (заметь, другим) вызывается PreTranslateMessage нужного мне потока. У меня кстати потоков несколько штук, поэтому важно, чтобы очередность доступа к общим данным строго соблюдалась, а не только лишь синхронизировалась. Я конечно понимаю, что и очередь тоже реализовать несложно, но вот если есть готовый механизм, почему бы не попробовать? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
takedo |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 501 Регистрация: 1.6.2005 Репутация: нет Всего: 3 |
Dreamer_0x01 Вообще-то когда ты вызываешь SendMessage() - да она ставится в очередь синхронных сообщений, но выйдешь ты из неё только тогда, когда отработает функция, которая будет вызвана обработчиком, вот её то и можно сразу вызвать обернув её в CriticalSec.Lock() CriticalSec.UnLock(); тогда в ней никого другого не будет (секцию объявляешь внутри функции да и статической пожалуй).
Добавлено @ 12:59 ну да ладно, делай как тебе удобнее, тут на вкус и цвет как говорится товарищей нет ![]() -------------------- я не гольфист - я хоккеист |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Спасибо, про это я точно не мог знать.
Вещь получилась обалденная и работает! Круто! "+" тебе за помощь в данном топике, моя идея начала потихоньку работать! Но осталось победить еще одну тонкость. Допустим, у нас не два потока, а три. (допустим поток1, поток2 и поток3). Поток 2 посылает потоку 1 синхронное сообщение, поток 1 начинает его обрабатывать, поток 2 ждет события. Все хорошо. Но в этот момент поток 3 тоже посылает синхронное сообщение потоку 1. И соответственно, он тоже замирает, и ждет установки события. Но беда в том, что когда поток 1 выполнит обработку сообщения потока 2, он установит событие, по которому разбудится не только поток 2, но и поток 3, что есть неправильно. По сему у меня мысли такие - либо использовать SuspendThread, тогда придется отказаться от событий (хотя, жаль), либо делать свою очередь сообщений. (что по-моему гораздо сложнее). Что скажешь на этот счет? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Скажу, что каждым потоком нужно управлять отдельно.
Нет, разбудится только один поток (событие-то с автосбросом), но вот какой... это никак неопределено. Правда, мы тут слегка путаем понятия. Есть поток, который thread, и есть поток -класс CMyThread. Все о чем мы говорили до этого, относится к классу CMyThread. А вот вызовы его методов происходят из разных потоков. Назовем "родным" тот поток, который создается AfxBeginThread для класса CMyThread, а внешним - поток, который вызывает нашу гипотетическую ф-ю SendThreadMessage. Надеюсь, ты как и я подразумевал, что она будет реализована как нестатический член класса CMyThread. Кстати, тогда флаги и\или события лучше тоже сделать его мемберами (нет никакого смысла заводить какие-то левые структуры). Так вот, а обработка сообщений производится в "родном" потоке. Ну, это нам Windows обеспечит, а вот то, что SendThreadMessage должна вызываться из внешнего потка, неплохо бы проверить (иначе ты сам себе deadlock устроишь, да и смысла никакого нет). Короче говоря, каждый поток, который желает так себя вести, обзаводится двумя событиями (ну или событие + флаг). И нет никаких проблем - все будут работать независимо. Правда, не могу не согласится с takedo насчет того, что все это можно реализовать без интерфейсного потока, и, возможно, получится даже проще. Я, честно говоря, тоже считаю, что если окна в потоке не нужны, то лучше обойтись рабочим потоком. Например, в одном из наших приложений, потоки устроены следующим образом. Каждый поток создает обязательное событие для завершения и произвольное число событий (или других объектов синхронизации). Каждому событию сопоставляется обработчик. Функция потока - это цикл ожидания WaitForMultipleObjects + обработка того, что просигналило или выход. Естественно, все это делает базовый код, а производным классам остается только определить обработчики. Спасибо тебе за +. -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Все так и сделано, это все я засунул в private-часть класса.
Проверил, вроде бы все нормально. Я создал приложение на основе диалога, в котором породил подобный поток, и запустил эту самую функцию. В обработчике сообщения вставил мессаджбокс. В итоге во время появления события я получал тот самый мессажбокс, но что особо порадовало - то, что полностью блокировалось GUI диалога, то есть он был полностью "замороженный" до тех пор, пока я не кликал по мессаджбоксу. То есть тот поток, который создал мессаджбокс (то есть в твоей терминологии. наш "родной" поток), работал, а поток, которому принадлежало диалоговое окно (то бишь внешний) спал, что собственно мне и нужно было. Не очень понял, про что это. Как это "обзаводится"? Добавлено @ 22:45
Хе-хе-хе ![]() Опять возвращаемся к мысли "А не создать ли нам фиктивное окно в потоке". Тогда функция SendThreadMessage() будет просто делать SendMessage() для нашего "фиктивного" окошка, производного от CWnd, у этого окошка мы переопределим PreTranslateMessage(), в котором сделаем PostThreadMessage() его зозяину, то бишь нашему потоку ;) Тогда механизм вызова функции SendThreadMessage() будет такой же, но вот накладные расходы на очереди сообщений, их ожидания и пр. возьмет уже система.... Главное в этом случае добиться того, чтобы оконная очередь сообщения обслуживалась именно нашим "родным" потоком... ![]() -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
А вот еще подумал, можно действительно для каждого потока, использующего данную функцию, завести пару таких событий.
То есть завести массив структур, содержащих в себе два этих самых CEvent и указатель на CWinThread, по умолчанию равный NULL. (допустим, ограничим его для начала 16 потоками, ряд ли мне когда-либо больше понадобится) Когда какой-то поток будет вызывать эту функцию, я буду осущетсвлять поиск элемента массива с нулевым указателем, присваивать этому указателю значение AfxGetThread, и собственно выполнять вышеуказанные действия с событиями. В обработчике события я буду делать WaitForMultipleObjects всех нужных событий, по коду события определять номер элемента ассива, сигналить второе событие, и очищать указатель на поток. Как думаешь, это нормально, или похоже на безумие? -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Да нет же, рабочий поток - этот как раз поток без очереди сообщений, и уж конечно без всяких окон. В противоположность интерфейстному.
На фига тебе отдельный массив структур. Заведи базовый класс потока, события - переменные класса, как и функция Send... и обработка. И храни себе массив указателей на потоки. "Эту" - это SendThreadMessage? Так ты в любом случае должен вызывать ее для конкретного потока. Т.е. клиент должен знать, к кому обращается. Иначе фигня какая-то получается. Надо бы тебе почетче сформулировать, какую именно задачу ты решаешь. А то у меня создается впечатление, что ты хочешь создать систему управления потоками "вообще", на все случаи жизни. Не бывает. ![]() -------------------- ... |
||||
|
|||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Так а ведь событий-то тоже должно быть много - на каждый поток, вызывающий извне фунцию SendThreadMessage() - по паре! Чтобы не получилось вышеописанной ситуации, когда много потоков ждут одного события, причем чужого. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Нет, так мы далеко зайдем
![]() Насколько вероятна ситуация, когда несколько потоков синхронно обратятся к одному? Даже если это возможно, то достаточно добавить в класс потока еще критическую секцию и прикрыть ею весь код SendTreadMessage. Тогда двух событий на поток достаточно. И будет у нас по принципу: кто первый, того и тапки. А остальные подождут. Сам подумай: даже если SendThreadMessage вызывается разными потоками, в результате-то будет работать только один (к которому обратились)! Т.е. в один момент может обрабатываться только чей-нибудь один запрос. Про чужое событие никто не узнает ![]() Даже если у тебя потоки хаотично друг к другу обращаются (синхронно!), и никто не хочет ждать, все равно придется как-то их в очередь строить... приоритеты назначать ... и понеслось ... в результате получаем новый Windows Kernel ... старый нафик выбрасываем (наш, конечно, лучше ![]() В общем, не увлекайся. В этом деле (в программировании) один из самых главных принципов - научится вовремя бить себя по рукам, и помнить, что лучшее - враг хорошего. ![]() -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Очень даже. У меня программа будет работать с несколькими прибораи одновременно по разным интерфейсам (ком-порты, Ethernet, и в перспективе еще и USB), на каждый планируется создать свой поток.
![]() Earnest, ты профи! ![]() Добавлено @ 18:52 А ведь точно, это мысль.. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||
|
|||||
Dreamer_0x01 |
|
||||||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
Ну что, уже достаточно давно пользуюсь своей консрукцией, пока работает.
может, тут есть какие-то подводные камни? Щас-то приложение маленькое, но вот на днях буду его очень сильно расширять. Вот код: собственно, класс
Описание класса
Использование
Вот у меня вопрос - правильно ли я сделал ReplyMessage(), или тут есть какие-то "подковырки"? ![]() -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
||||||
|
|||||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Вроде нормально... раз пока работает...
![]() Но если собираешься сильно расширять, то используй вместо CRITICAL_SECTION CCriticalSection, а вместо Enter/Leave - CSingleLock. Во-первых много строчек кода уйдет, что само по себе неплохо. Во-вторых, смесь CEvent и "просто" CRITICAL_SECTION выглядит, как бы это помягче сказать ![]() В-третьих - код будет безопаснее по отношению к исключениям - это тебе обеспечит идиома "захват ресурса есть инициализация". В-четвертых, вызовы ...ResetEvent в конструкторе совершенно излишни, т.к. CEvent по умолчанию создается не в сигнальном состоянии. И зачем все эти this-> ? -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
НУ в двух потоках работает все прекрасно. Единственное, почему-то были глюки при выхове функций из...того же самого потока. Правда, с этим я постепенно и сам разберусь, может быть, неправильно что-то вызываю. Вот скоро буду проверять на четырех, там и поглядим.
Ага. Сделаю. Видишь ли, я самоучка, и до чего первого дошел, то и прижилось во всех программах ![]() Кстати, где бы почитать что-то вразумительное про эти самые исключения, русскоязычное? До сих пор толком не понимаю, что это такое и зачем нужно. А так бысрее код набирать текст программы - набираешь this->, и студия тебе выдает списочек всех членов класса, удобно, нажал одну-две клавиши вместо десятка - и элемент вписан. Только лишь ради этого ;) Компилятор же я так понял все равно все лишнее выкинет? Это сообщение отредактировал(а) Dreamer_0x01 - 6.2.2006, 20:09 -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Скорее вставит, если этого this-> нет. Формально все правильно, но ИМХО, код более громоздкий и поэтому хуже читаемый. Я предпочитаю классовые переменные с префиксом "m_" делать, чтобы сразу видно было ху из ху. А скорость набора на скорость конечную написания кода не влияет. Кстати, у тебя есть Visual Assist? Если нет, найди и поставь, очень рекомендую (и в смысле автодополнения тоже).
Исключениям посвящена изрядная часть книги Саттера "Решение сложных задач на С++", здесь на форуме в разделе C++ обсуждалась, может и ссылки на электронную версию есть. И его же продолжение "Новые сложные задачи на С++". А еще, по-моему Мейерс на эту тему писал: "50 советов по эффективному использованию С++", "Еще 35 советов" про то же самое, а также "Эффективное использование STL". Названия приблизительные. Я бы советовала начать с Мейерса, мне кажется у него более доступно. Все книжки небольшие, и все из серии must read. -------------------- ... |
|||
|
||||
Dreamer_0x01 |
|
|||
![]() Терминатор ![]() ![]() Профиль Группа: Участник Сообщений: 780 Регистрация: 14.4.2005 Где: Санкт-Петербург Репутация: 9 Всего: 12 |
А вот это недавече как сегодня где-то видел, но смутило кричащее название, и пропустил. Завтра в поиске восстановлю сайтик, где это было выложено. Нет, не стоит. А что эта штука кроме подсветки кода делает? Добавлено @ 00:10 я понимаю, но когда я сам же забываю, как точно называется имя переменной - то приходится делать именно так. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 87 Всего: 183 |
Ну это переводчики постарались, оригинальное название "Exceptional C++". Там просто стиль изложения такой: ставится задача, потом решается. VisualAssist у меня так давно, что я уже не помню, что он делает, а что сам MSVC. По-моему, я автодополнение MSVC и его же броузинг кода просто не использую, а использую VisualAssist (потому что лучше). Еще он вроде автоматически исправляет мелкие ошибки набора, показывает контекст текущего выражения и его определение. Плюс настраиваемые функции: генерация блоков текста по шаблонам. Очень удобно, например, в новые файлы стандартные шапки вставлять. -------------------- ... |
|||
|
||||
![]() ![]() ![]() |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |