Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Аналог InvokeRequired 
V
    Опции темы
Brodyaga
Дата 4.2.2009, 12:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Всем здравствуйте! Есть ли в С++ или MFC какой-нить аналог си шарповского InvokeRequired/BeginInvoke??
PM MAIL   Вверх
Brodyaga
Дата 5.2.2009, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Неужели никто не знает?! Другими словами мне нужно асинхронное выполнение какого либо метода.
PM MAIL   Вверх
Earnest
Дата 5.2.2009, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Асинхронное? В смысле выполнение не в момент вызова, а позже, но тоже в главном потоке? Тогда PostMessage какому-нибудь окну или приложению + соответствующий обработчик этого сообщения.


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


Опытный
**


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

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



Наверное немного неправильно выразился... Вообще на си шарпе есть такая конструкция:

Код

public partial class FormMain : Form
{
        ....

        public void Method(String str)
        {
            if (!this.InvokeRequired)
            {
              .....
            }
            else
                this.BeginInvoke(new MethodDelegate(Method), str);
        }

        ....
}


Сначала проверяем с помощью InvokeRequired, была ли вызвана функция Method из главного потока или нет, ежели нет, то вызываем её заново с тем же параметром но из главного потока. Вот мне надо такое же реализовать на обычном С или MFC... Как это сделать подскажите пожалуйста?
PM MAIL   Вверх
Earnest
Дата 5.2.2009, 14:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Т.е. некто вызывает функцию Method бог знает откуда, а тебе нужно, чтобы она гарантированно выполнялась в главном потоке, я правильно поняла?
Готового такого механизма нет, но можно воспользоваться тем фактом, что оконная функция (все обработчики) всегда выполняются в том потоке, которому принадлежит окно. Главный поток (если интерфейсных потоков несколько) - это поток, которому принадлежит главное окно. Т.е. чтобы гарантировать выполнение функции в главном потоке, нужно просто вызвать ее из какого-то обработчика главного окна. А инициировать вызов - послать какое-то юзеровское сообщение главному окну.
Чтобы не парить мозги вызывающему коду, можно спрятать все это дело внутрь твоего класса:

Код

void CMainForm::Method (CString str)
{
   if (AfxGetApp()==AfxGetThread()) 
  {
       // мы в главном потоке
       // делаем что надо
  }
   else
   {
        // запихиваем куда-нибудь аргументы и указатель на функцию-член, который нужно вызвать
        // и посылаем сами себе спец-сообщение; здесь предполагается, что CMainForm - это потомок CWnd
        // с помощью WPARAM и LPARAM  можно передавать простые аргументы и указатель на метод
        ::SendMessage (m_hWnd, XXM_INVOKE, ...);   
   }
}

// обработчик INVOKE, который нужно добавить в карту сообщений окна
LRESULT CMainForm::OnInvoke (WPARAM, LPARAM)
{
    // извлекаете строку-аргумент оттуда, куда вы ее засунули
    CString str = ...
    Method (str);
}


Вызов Method из любого потка будет выглядеть как синхронный (потому что мы используем SendMessage);
Этим можно воспользоваться, чтобы просто передать указатель на вашу строкe-аргумент в LPARAM - она гарантированно будет существовать в момент вызова.


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


Опытный
**


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

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



Этот способ я знаю, просто думал может есть готовый механизм... Ещё можно также переопределить оконную процедуру и в ней всю логику обрабатывать... 
Но хотелось бы всё же, чтобы была такая же функция как BeginInvoke в С#... Первый параметр делегат на любую функцию(указатель) далее идёт любое количество параметров любого типа для функции на которую указывает делегат. Внутри себя BeginInvoke передаёт эти параметры в функцию делегата... Попытался реализовать такое в С++.

Итак, что должна делать функция-аналог сишарповской BeginInvoke:
1.Принимать делегат(указатель) на любую функцию
2.Принимать любое количество параметров любых типов.
3.Передать указатель на делегат и все параметры через SendMessage в обработчик
4.Обработчик сообщения вызывает функцию на которую указывает делегат даже не зная, что это за функция
5.Обработчик сообщения передаёт в функцию на которую указывает делегат все переданные параметры через SendMessage

Сделал делегат с общим базовым классом, который и передаёца в мой сишный вариант BeginInvoke. Но вот проблема... Как передать параметры через SendMessage и затем в обработчике сообщения их передать в функцию делегата, если набор параметров и их типы всегда разные???
PM MAIL   Вверх
Earnest
Дата 9.2.2009, 09:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(Brodyaga @  7.2.2009,  15:23 Найти цитируемый пост)
Сделал делегат с общим базовым классом, который и передаёца в мой сишный вариант BeginInvoke. Но вот проблема... Как передать параметры через SendMessage и затем в обработчике сообщения их передать в функцию делегата, если набор параметров и их типы всегда разные??? 


Для любого числа аргументов сделать и, так, чтобы это было удобно (т.е. с естественным синтаксисом),  нельзя, да и не нужно. 
Основная проблема - переменный нужно где хранить, в параметры SendMessage можно упаковать только 2 инта или 2 указателя. Значит, нужна динамическая структура, где будут храниться переменные пока это необходимо. 
Другая проблема - тип переменной может быть любым, т.е. нужно обобщенное хранилище типа варианта. Я обычно использую boost::any. А проблема с разным числом параметров решается шаблонами. Я обычно ограничиваюсь 3-4, больше аргументов приличная функция использовать не должна.

Я делала что-то подобное, но не для передачи управления между потоками, а для пересылки команд с аргументами через WM_COMMAND между модулями. Но принцип хранения-извлечения переменныйх можно использовать тот же. Если хочешь, могу дать код.


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


Опытный
**


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

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



Цитата

Другая проблема - тип переменной может быть любым, т.е. нужно обобщенное хранилище типа варианта. Я обычно использую boost::any.


Ну boost я не использую.. если использовать обобщённое хранилище типа вариант и передавать его через сендмесседж например сообщением WM_COPYDATA, то как я в обработчике узнаю какой вариант к какому типу мне преобразовывать при передаче параметров в функцию на которую указывает мой делегат?

Цитата

А проблема с разным числом параметров решается шаблонами. 


Так я её и решил, так как делегат свой я и делал на основе шаблонов. Запихнул туда ещё один класс такого типа
Код

class BaseDataObject
{
}


#define PARAMS C1,C1
#define COMPOSITION_DATA C1 c1; C1 c2;

template<PARAMS>
class BaseObject: BaseDataObject
{
 COMPOSITION_DATA
}


ну вот чтото типа того.. тоесть для делегата с определённым набором параметров существует и определённый класс хранящий данные для функции! а общий класс для делегата выглядит примерно так

template<TType>
class IDelegate
{
 TType Invoke(BaseDataObject);
}


Но ещё одна проблема заключается в передаче через сенд мессадж указателя на свой делегат, так как ЕДИНОГО базового класса для него нет.. вернее есть, но так как используюца шаблоны он всегда разный... и в обработчике сообщения посланного сендмессаджом не ясно к какому типу преобразовывать делегат толи к IDelegate<void> а толи IDelegate<int> к примеру... а хочеца ЛЮБОЙ делегат просто преобразовать к типу IDelegate и вызвать метод на который делегат указывает ,как в с#... Как нить можно сделать единный базовый класс??? в с# то наверное делегаты внутри реализованы таким образом, что в базовом классе у функции возвращаемое значение типа Object ;) а там всё object smile)) вот так....

PM MAIL   Вверх
Brodyaga
Дата 13.2.2009, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Вообщем ладно.. Наверное так нельзя сделать, да и не к чему. Остановлюсь на варианте, о котором думал сначала.. Тоесть обойдусь SendMessage. Тема закрыта.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




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


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

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