![]() |
|
|
![]()
|
|
| 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() - по паре! Чтобы не получилось вышеописанной ситуации, когда много потоков ждут одного события, причем чужого. -------------------- Нет ничего невозможного. Есть цели, и есть время и силы на их достижение. |
|||
|
||||
![]()
|
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |