Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как сделать аналог 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   Вверх
Dreamer_0x01
Дата 20.1.2006, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



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

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


Ну хочется мне именно так попробовать сделать, и посмотреть, что получится, что ж тут поделать?
smile


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


Эксперт
****


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

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



Dreamer_0x01, извини, отвлекоась на семейные проблемы...
Если ты хочешь сделать так, как я написала, без окон, тебе надо перекрыть PumpMessage, а не PreTranslateMessage - потому что вторая вызывается ДО, а не после обработки сообщения.
Если стандартная PumpMessage возвращает TRUE, вызывай SetEvent.
Событие должно быть с автосбросом! Флаг нужно изменять атомарно! Не надо писать while (flag) в потоке!
Ну ладно, английский ты не любишь, но код MFC кто мешает посмотреть?!!!



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


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


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

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



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

Флаг нужно изменять атомарно!

Не понял, это что значит?



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


Эксперт
****


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

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



Это означает, что нужно гарантировать, что никто не обратится к флагу, пока операция изменения не завершена - та самая межпоточная безопасность. Для защиты более сложных объектов приходится использовать как минимум critical section, но для int'ов есть специальные функции Interlocked***. Тебе подойдет InterlockedExchange.


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


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


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

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



Earnest

Я делаю так(допустим, проверяю флаг FLAG1 внутри структуры MyStruct)
Код

typedef struct {
char FLAG1;
CRITICAL_SECTION cs;
//другие поля
}MYSTRUCT;


И в потоках делаю следующее:
Код

//при инициализации потока в него передано MYSTRUCT * MyStruct;
{
//какие-то действия...

//этап проверки состояния флага:

char Temp_Flag;
::EnterCriticalSection(&MyStruct->cs);
Temp_Flag=MyStruct->FLAG1;
::LeaveCriticalSection(&MyStruct->cs);

if(TempFlag==МОЯ_КАКАЯ_ТО_КОНСТАНТА)
{
//какие-то действия
}
//ну и так далее
}


Ты это имела в виду, или что-то принципиально другое?


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


Эксперт
****


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

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



Это, это, только зачем так сложно...
Если речь идет только о защите флага, то проще (короче и нагляднее) использовать функции Interlocked. Например:
Код

struct CMyStruct
{
   ...
   LONG m_SyncFlag;   // LONG - потому что так хочет InterlockedExchange
};

Далее, в коде обработки собщений:

Код

if (InterlockedExchange(&pMyStruct->m_SyncFlag,0))
{
   // какие-то действия, видимо - SetEvent
}


В этом фрагменте InterlockedExchange возвращает текущее значение флага и записывает туда 0 (мы ведь хотим, чтобы флаг, поставленный в SendThreadMessage, сработал единожды). И все это делается гарантированно атомарно. Соответственно, устанавливать флаг нужно вызовом InterlockedExchange((&pMyStruct->m_SyncFlag,1).

Написала я этот код и подумала: здорово похоже на авто-событие. Там, может, событие и использовать? Еще одно. Т.е. примерно так:

Код

struct СMySync
{
   CEvent m_evSync;
   CEvent m_evReady;   
};

#define TIMEOUT 15000

LRESULT CMyThread::SendThreadMessage(...параметры...)
{
   m_pMySync->m_evSync.SetEvent();
   PostThreadMessage(...);
   m_pMySync->m_evReady.Lock(TIMEOUT); // то же самое, что WaitForSingleObject(m_pMySync->m_evReady,TIMEOUT);
   ...
}

Обработчик ()
{
   ...
   if (m_pMySync->m_evSync.Lock(0)) 
   {
      ...
      m_pMySync->m_evReady.SetEvent();
   }
}


PS
MFC-обертки объектов ядра удобнее и нагляднее "родных" функций API.


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


Опытный
**


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

Репутация: нет
Всего: 3



Dreamer_0x01
Во чего я подумал... Если у тебя в потоке нет окна, тогда вообще нет необходимости слать сообщения и вызывать страшные функции PreTranslateMessage и др. Создавай просто функцию bool func(); и ее вызывай. Это не будет отличатся от SendMessage, так как любое сообщение - суть вызов функции (в данном случае func()), ты ведь можешь её и сразу вызвать. А сообщения нужны лишь для того, чтобы не парится с синхронизацией, так как они обрабатываеются потоком, создавшим окно(посмотри ветку где куча народу спорила о синхронизации, я там пример из рихтера приводил, правда никто вроде бы не обратил внимания smile ) и только им => ничего и синхронизировать не надо. Но если ты шлешь мессаги из разных потоков, тогда можно и простыми объектами синхронизации обойтись smile Но вот уже четыре дня чешется рука тебе плюс поставить - за то что реализовал интерфейсный поток(мне вот лень было для пробы делать smile ) вот и ставлю, благо есть у меня ещё на енто право smile


--------------------
я не гольфист - я хоккеист
PM MAIL   Вверх
Dreamer_0x01
Дата 23.1.2006, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


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


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

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



takedo
Спасибо за поддержку, вот уж сюрприз ;)

Цитата(takedo @ 23.1.2006, 08:13 Найти цитируемый пост)

А сообщения нужны лишь для того, чтобы не парится с синхронизацией,

Вот именно для этого.

Цитата(takedo @ 23.1.2006, 08:13 Найти цитируемый пост)

так как любое сообщение - суть вызов функции (в данном случае func()), ты ведь можешь её и сразу вызвать

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




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


Опытный
**


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

Репутация: нет
Всего: 3



Dreamer_0x01 Вообще-то когда ты вызываешь SendMessage() - да она ставится в очередь синхронных сообщений, но выйдешь ты из неё только тогда, когда отработает функция, которая будет вызвана обработчиком, вот её то и можно сразу вызвать обернув её в CriticalSec.Lock() CriticalSec.UnLock(); тогда в ней никого другого не будет (секцию объявляешь внутри функции да и статической пожалуй).
Добавлено @ 12:59
ну да ладно, делай как тебе удобнее, тут на вкус и цвет как говорится товарищей нет smile


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


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


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

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



Цитата(Earnest @ 22.1.2006, 19:13 Найти цитируемый пост)

Соответственно, устанавливать флаг нужно вызовом InterlockedExchange((&pMyStruct->m_SyncFlag,1).

Спасибо, про это я точно не мог знать.

Цитата(Earnest @ 22.1.2006, 19:13 Найти цитируемый пост)

Написала я этот код и подумала: здорово похоже на авто-событие. Там, может, событие и использовать? Еще одно. Т.е. примерно так:

Вещь получилась обалденная и работает! Круто!

"+" тебе за помощь в данном топике, моя идея начала потихоньку работать!

Но осталось победить еще одну тонкость. Допустим, у нас не два потока, а три. (допустим поток1, поток2 и поток3).
Поток 2 посылает потоку 1 синхронное сообщение, поток 1 начинает его обрабатывать, поток 2 ждет события. Все хорошо. Но в этот момент поток 3 тоже посылает синхронное сообщение потоку 1. И соответственно, он тоже замирает, и ждет установки события. Но беда в том, что когда поток 1 выполнит обработку сообщения потока 2, он установит событие, по которому разбудится не только поток 2, но и поток 3, что есть неправильно.

По сему у меня мысли такие - либо использовать SuspendThread, тогда придется отказаться от событий (хотя, жаль), либо делать свою очередь сообщений. (что по-моему гораздо сложнее).

Что скажешь на этот счет?


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


Эксперт
****


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

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



Скажу, что каждым потоком нужно управлять отдельно.
Цитата(Dreamer_0x01 @ 23.1.2006, 17:01 Найти цитируемый пост)

он установит событие, по которому разбудится не только поток 2, но и поток 3, что есть неправильно

Нет, разбудится только один поток (событие-то с автосбросом), но вот какой... это никак неопределено.

Правда, мы тут слегка путаем понятия. Есть поток, который thread, и есть поток -класс CMyThread. Все о чем мы говорили до этого, относится к классу CMyThread. А вот вызовы его методов происходят из разных потоков.
Назовем "родным" тот поток, который создается AfxBeginThread для класса CMyThread, а внешним - поток, который вызывает нашу гипотетическую ф-ю SendThreadMessage.
Надеюсь, ты как и я подразумевал, что она будет реализована как нестатический член класса CMyThread. Кстати, тогда флаги и\или события лучше тоже сделать его мемберами (нет никакого смысла заводить какие-то левые структуры).
Так вот, а обработка сообщений производится в "родном" потоке. Ну, это нам Windows обеспечит, а вот то, что SendThreadMessage должна вызываться из внешнего потка, неплохо бы проверить (иначе ты сам себе deadlock устроишь, да и смысла никакого нет).

Короче говоря, каждый поток, который желает так себя вести, обзаводится двумя событиями (ну или событие + флаг). И нет никаких проблем - все будут работать независимо.

Правда, не могу не согласится с takedo насчет того, что все это можно реализовать без интерфейсного потока, и, возможно, получится даже проще. Я, честно говоря, тоже считаю, что если окна в потоке не нужны, то лучше обойтись рабочим потоком.

Например, в одном из наших приложений, потоки устроены следующим образом.
Каждый поток создает обязательное событие для завершения и произвольное число событий (или других объектов синхронизации). Каждому событию сопоставляется обработчик. Функция потока - это цикл ожидания WaitForMultipleObjects + обработка того, что просигналило или выход. Естественно, все это делает базовый код, а производным классам остается только определить обработчики.

Спасибо тебе за +.



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


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


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

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



Цитата(Earnest @ 23.1.2006, 19:10 Найти цитируемый пост)

Надеюсь, ты как и я подразумевал, что она будет реализована как нестатический член класса CMyThread. Кстати, тогда флаги и\или события лучше тоже сделать его мемберами (нет никакого смысла заводить какие-то левые структуры).

Все так и сделано, это все я засунул в private-часть класса.
Цитата(Earnest @ 23.1.2006, 19:10 Найти цитируемый пост)

Ну, это нам Windows обеспечит, а вот то, что SendThreadMessage должна вызываться из внешнего потка, неплохо бы проверить

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

Цитата(Earnest @ 23.1.2006, 19:10 Найти цитируемый пост)

Короче говоря, каждый поток, который желает так себя вести, обзаводится двумя событиями (ну или событие + флаг). И нет никаких проблем - все будут работать независимо.

Не очень понял, про что это. Как это "обзаводится"?
Добавлено @ 22:45
Цитата(Earnest @ 23.1.2006, 19:10 Найти цитируемый пост)

Я, честно говоря, тоже считаю, что если окна в потоке не нужны, то лучше обойтись рабочим потоком.

Хе-хе-хе smile
Опять возвращаемся к мысли "А не создать ли нам фиктивное окно в потоке".

Тогда функция SendThreadMessage() будет просто делать SendMessage() для нашего "фиктивного" окошка, производного от CWnd, у этого окошка мы переопределим PreTranslateMessage(), в котором сделаем PostThreadMessage() его зозяину, то бишь нашему потоку ;)

Тогда механизм вызова функции SendThreadMessage() будет такой же, но вот накладные расходы на очереди сообщений, их ожидания и пр. возьмет уже система.... Главное в этом случае добиться того, чтобы оконная очередь сообщения обслуживалась именно нашим "родным" потоком...
smile



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


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


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

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



А вот еще подумал, можно действительно для каждого потока, использующего данную функцию, завести пару таких событий.
То есть завести массив структур, содержащих в себе два этих самых CEvent и указатель на CWinThread, по умолчанию равный NULL. (допустим, ограничим его для начала 16 потоками, ряд ли мне когда-либо больше понадобится) Когда какой-то поток будет вызывать эту функцию, я буду осущетсвлять поиск элемента массива с нулевым указателем, присваивать этому указателю значение AfxGetThread, и собственно выполнять вышеуказанные действия с событиями.
В обработчике события я буду делать WaitForMultipleObjects всех нужных событий, по коду события определять номер элемента ассива, сигналить второе событие, и очищать указатель на поток.

Как думаешь, это нормально, или похоже на безумие?


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


Эксперт
****


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

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



Цитата(Dreamer_0x01 @ 23.1.2006, 22:31 Найти цитируемый пост)

Опять возвращаемся к мысли "А не создать ли нам фиктивное окно в потоке".

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

Цитата(Dreamer_0x01 @ 24.1.2006, 17:52 Найти цитируемый пост)

То есть завести массив структур, содержащих в себе два этих самых CEvent и указатель на CWinThread

На фига тебе отдельный массив структур.
Заведи базовый класс потока, события - переменные класса, как и функция Send... и обработка.
И храни себе массив указателей на потоки.

Цитата(Dreamer_0x01 @ 24.1.2006, 17:52 Найти цитируемый пост)

Когда какой-то поток будет вызывать эту функцию, я буду осущетсвлять поиск элемента массива с нулевым указателем, присваивать этому указателю значение AfxGetThread, и собственно выполнять вышеуказанные действия с событиями.

"Эту" - это SendThreadMessage? Так ты в любом случае должен вызывать ее для конкретного потока. Т.е. клиент должен знать, к кому обращается. Иначе фигня какая-то получается.
Надо бы тебе почетче сформулировать, какую именно задачу ты решаешь. А то у меня создается впечатление, что ты хочешь создать систему управления потоками "вообще", на все случаи жизни.
Не бывает. smile Или бывает, но
Цитата(Dreamer_0x01 @ 24.1.2006, 17:52 Найти цитируемый пост)

похоже на безумие






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


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


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

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



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

На фига тебе отдельный массив структур.
Заведи базовый класс потока, события - переменные класса, как и функция Send... и обработка.
И храни себе массив указателей на потоки.

Так а ведь событий-то тоже должно быть много - на каждый поток, вызывающий извне фунцию SendThreadMessage() - по паре! Чтобы не получилось вышеописанной ситуации, когда много потоков ждут одного события, причем чужого.


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


Эксперт
****


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

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



Нет, так мы далеко зайдем smile
Насколько вероятна ситуация, когда несколько потоков синхронно обратятся к одному? Даже если это возможно, то достаточно добавить в класс потока еще критическую секцию и прикрыть ею весь код SendTreadMessage. Тогда двух событий на поток достаточно. И будет у нас по принципу: кто первый, того и тапки. А остальные подождут.
Сам подумай: даже если SendThreadMessage вызывается разными потоками, в результате-то будет работать только один (к которому обратились)! Т.е. в один момент может обрабатываться только чей-нибудь один запрос.

Про чужое событие никто не узнает smile , ведь вся обработка событий инкапсулирована внутри класса потока, и события у него свои...

Даже если у тебя потоки хаотично друг к другу обращаются (синхронно!), и никто не хочет ждать, все равно придется как-то их в очередь строить... приоритеты назначать ... и понеслось ... в результате получаем новый Windows Kernel ... старый нафик выбрасываем (наш, конечно, лучше smile ) ...

В общем, не увлекайся. В этом деле (в программировании) один из самых главных принципов - научится вовремя бить себя по рукам, и помнить, что лучшее - враг хорошего. smile


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


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


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

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



Цитата(Earnest @ 25.1.2006, 18:07 Найти цитируемый пост)

Насколько вероятна ситуация, когда несколько потоков синхронно обратятся к одному?

Очень даже. У меня программа будет работать с несколькими прибораи одновременно по разным интерфейсам (ком-порты, Ethernet, и в перспективе еще и USB), на каждый планируется создать свой поток.

Цитата(Earnest @ 25.1.2006, 18:07 Найти цитируемый пост)

Даже если это возможно, то достаточно добавить в класс потока еще критическую секцию и прикрыть ею весь код SendTreadMessage

smile точно! Как я не догадался... Все гениальное - просто!
Earnest, ты профи! smile
Добавлено @ 18:52
Цитата(Earnest @ 25.1.2006, 18:07 Найти цитируемый пост)

придется как-то их в очередь строить... приоритеты назначать ... и понеслось ... в результате получаем новый Windows Kernel ... старый нафик выбрасываем (наш, конечно, лучше  )


А ведь точно, это мысль..



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


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


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

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



Ну что, уже достаточно давно пользуюсь своей консрукцией, пока работает.


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

Вот код:

собственно, класс
Код

struct SYNCSTRUCT{//синхронизирующая структура
    CEvent SyncDetect;//определяет, была ли посылка синхронного сообщения
    CEvent EventReady;//готовность обработки синхронного сообщения
    CRITICAL_SECTION cs;
};

class MyThread : public CWinThread
{
    DECLARE_DYNCREATE(MyThread)
private:
    SYNCSTRUCT m_SyncEvents;
protected:
    MyThread();           // protected constructor used by dynamic creation
    virtual ~MyThread();
    DECLARE_MESSAGE_MAP()

public:
    virtual BOOL InitInstance();
    virtual int ExitInstance();
    virtual BOOL PumpMessage();
    BOOL SendThreadMessage(UINT message, WPARAM wParam, LPARAM lParam);//собственно, все ради этого
protected:
    void ReplyMessage(void);
};


Описание класса
Код

IMPLEMENT_DYNCREATE(MyThread, CWinThread)

MyThread::MyThread()
{
    this->m_SyncEvents.EventReady.ResetEvent();//во избежание взаимной блокировки
    this->m_SyncEvents.SyncDetect.ResetEvent();
    ::InitializeCriticalSection(&this->m_SyncEvents.cs);
}

MyThread::~MyThread()
{
    ::DeleteCriticalSection(&this->m_SyncEvents.cs);
}

BOOL MyThread::InitInstance()
{
    this->m_bAutoDelete=TRUE;
    return TRUE;
}

int MyThread::ExitInstance()
{
    return CWinThread::ExitInstance();
}

BEGIN_MESSAGE_MAP(MyThread, CWinThread)
END_MESSAGE_MAP()

BOOL MyThread::PumpMessage()
{
    BOOL result= CWinThread::PumpMessage();
    if(this->m_SyncEvents.SyncDetect.Lock(0))
    {
        this->m_SyncEvents.EventReady.SetEvent();
    }
    return result;
}

BOOL MyThread::SendThreadMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
    ::EnterCriticalSection(&this->m_SyncEvents.cs);
    this->m_SyncEvents.SyncDetect.SetEvent();
    BOOL result=this->PostThreadMessage(message,wParam,lParam);
    this->m_SyncEvents.EventReady.Lock();
    ::LeaveCriticalSection(&this->m_SyncEvents.cs);
    return result;
}

void MyThread::ReplyMessage(void)
{
    this->m_SyncEvents.EventReady.SetEvent();
}



Использование
Код

class WorkThread : public MyThread
{
//и понеслась вставлять обработчики своих сообщений
}

//а в самом приложении сначала объявляем
WorkThread * m_WorkThread;

//потом делаем 
    CRuntimeClass* prt = RUNTIME_CLASS( WorkThread );
    ASSERT( lstrcmp( prt->m_lpszClassName, "WorkThread" )  == 0 );
    this->m_WorkThread=(WorkThread*)AfxBeginThread(prt);

//ну и далее собственно уже можно слать сообщения: )
this->m_WorkThread->SendThreadMessage(/*......*/);

//ну а убиваем поток так:
this->m_WorkThread->PostThreadMessage(WM_QUIT,0,0);



Вот у меня вопрос - правильно ли я сделал ReplyMessage(), или тут есть какие-то "подковырки"? smile




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


Эксперт
****


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

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



Вроде нормально... раз пока работает... smile

Но если собираешься сильно расширять, то используй вместо CRITICAL_SECTION CCriticalSection, а вместо Enter/Leave - CSingleLock.
Во-первых много строчек кода уйдет, что само по себе неплохо. Во-вторых, смесь CEvent и "просто" CRITICAL_SECTION выглядит, как бы это помягче сказать smile ... странно.
В-третьих - код будет безопаснее по отношению к исключениям - это тебе обеспечит идиома "захват ресурса есть инициализация".
В-четвертых, вызовы ...ResetEvent в конструкторе совершенно излишни, т.к. CEvent по умолчанию создается не в сигнальном состоянии.

И зачем все эти this-> ?


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


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


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

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



Цитата(Earnest @ 6.2.2006, 18:41 Найти цитируемый пост)

Вроде нормально... раз пока работает...

НУ в двух потоках работает все прекрасно. Единственное, почему-то были глюки при выхове функций из...того же самого потока. Правда, с этим я постепенно и сам разберусь, может быть, неправильно что-то вызываю.
Вот скоро буду проверять на четырех, там и поглядим.
Цитата(Earnest @ 6.2.2006, 18:41 Найти цитируемый пост)

используй вместо CRITICAL_SECTION CCriticalSection, а вместо Enter/Leave - CSingleLock

Ага. Сделаю. Видишь ли, я самоучка, и до чего первого дошел, то и прижилось во всех программах smile

Цитата(Earnest @ 6.2.2006, 18:41 Найти цитируемый пост)

В-третьих - код будет безопаснее по отношению к исключениям

Кстати, где бы почитать что-то вразумительное про эти самые исключения, русскоязычное?
До сих пор толком не понимаю, что это такое и зачем нужно.

Цитата(Earnest @ 6.2.2006, 18:41 Найти цитируемый пост)

И зачем все эти this-> ?

А так бысрее код набирать текст программы - набираешь this->, и студия тебе выдает списочек всех членов класса, удобно, нажал одну-две клавиши вместо десятка - и элемент вписан. Только лишь ради этого ;)
Компилятор же я так понял все равно все лишнее выкинет?

Это сообщение отредактировал(а) Dreamer_0x01 - 6.2.2006, 20:09


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


Эксперт
****


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

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



Цитата(Dreamer_0x01 @ 6.2.2006, 19:52 Найти цитируемый пост)

Компилятор же я так понял все равно все лишнее выкинет?

Скорее вставит, если этого this-> нет. Формально все правильно, но ИМХО, код более громоздкий и поэтому хуже читаемый. Я предпочитаю классовые переменные с префиксом "m_" делать, чтобы сразу видно было ху из ху. А скорость набора на скорость конечную написания кода не влияет. Кстати, у тебя есть Visual Assist? Если нет, найди и поставь, очень рекомендую (и в смысле автодополнения тоже).

Цитата(Dreamer_0x01 @ 6.2.2006, 19:52 Найти цитируемый пост)

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

Исключениям посвящена изрядная часть книги Саттера "Решение сложных задач на С++", здесь на форуме в разделе C++ обсуждалась, может и ссылки на электронную версию есть.
И его же продолжение "Новые сложные задачи на С++". А еще, по-моему Мейерс на эту тему писал: "50 советов по эффективному использованию С++", "Еще 35 советов" про то же самое, а также "Эффективное использование STL". Названия приблизительные.
Я бы советовала начать с Мейерса, мне кажется у него более доступно. Все книжки небольшие, и все из серии must read.



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


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


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

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



Цитата(Earnest @ 6.2.2006, 22:11 Найти цитируемый пост)

"Решение сложных задач на С++"


А вот это недавече как сегодня где-то видел, но смутило кричащее название, и пропустил. Завтра в поиске восстановлю сайтик, где это было выложено.

Цитата(Earnest @ 6.2.2006, 22:11 Найти цитируемый пост)

Кстати, у тебя есть Visual Assist

Нет, не стоит. А что эта штука кроме подсветки кода делает?
Добавлено @ 00:10
Цитата(Earnest @ 6.2.2006, 22:11 Найти цитируемый пост)

А скорость набора на скорость конечную написания кода не влияет

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



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


Эксперт
****


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

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



Цитата(Dreamer_0x01 @ 7.2.2006, 00:08 Найти цитируемый пост)

А вот это недавече как сегодня где-то видел, но смутило кричащее название, и пропустил. Завтра в поиске восстановлю сайтик, где это было выложено.

Ну это переводчики постарались, оригинальное название "Exceptional C++".
Там просто стиль изложения такой: ставится задача, потом решается.

Цитата(Dreamer_0x01 @ 7.2.2006, 00:08 Найти цитируемый пост)

Нет, не стоит. А что эта штука кроме подсветки кода делает?

VisualAssist у меня так давно, что я уже не помню, что он делает, а что сам MSVC. По-моему, я автодополнение MSVC и его же броузинг кода просто не использую, а использую VisualAssist (потому что лучше). Еще он вроде автоматически исправляет мелкие ошибки набора, показывает контекст текущего выражения и его определение. Плюс настраиваемые функции: генерация блоков текста по шаблонам. Очень удобно, например, в новые файлы стандартные шапки вставлять.



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


 




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


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

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