Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Нестатический метод класса в потоке


Автор: null56 1.3.2010, 18:24
Всем привет
Задача: пытаюсь создать метод класса, который бы работал в потоке
Метод класса
Код

private:
            DWORD WINAPI create_thread(LPVOID lpParam);

Вызов №1:
Код

CreateThread(NULL, 0, create_thread, lpParameter, 0, &m_ThreadId);

Цитата

error C3867: 'Thread::create_thread': function call missing argument list; use '&Thread::create_thread' to create a pointer to member

Ок... вызов №2
Код

m_Thread = CreateThread(NULL, 0, &Thread::create_thread, lpParameter, 0, &m_ThreadId);

Цитата

error C2664: 'CreateThread' : cannot convert parameter 3 from 'DWORD (__stdcall Thread::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE'

Приведение типа (хоть оно и нерекомендовано в мсдн) не помогло... вызов №3
Код

m_Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Thread::create_thread, lpParameter, 0, &m_ThreadId);

Цитата

'type cast' : cannot convert from 'DWORD (__stdcall Thread::* )(LPVOID)' to 'LPTHREAD_START_ROUTINE'


Итог: если объявить функцию статичной, компилятор пропускает
Вопрос: Неужели низя передать нестатический метод класса в поток???

Заранее благодарен за помощь

ЗЫ: вызовы произвожу также из метода этого же класса

Добавлено через 11 минут и 43 секунды
я могу лишь предположить, что несоответствие происходит из - за неявного параметра this перед именем функции
если моё предположение верно, то реально ли передать метод в поток?

Автор: null56 1.3.2010, 18:40
в соседней теме, смотрю, человек передал через объект через this в статику... похоже, что нельзя

Автор: azesmcar 1.3.2010, 18:47
Была уже такая тема (и не одна). 

http://forum.vingrad.ru/forum/topic-254872/kw-%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B8-%D1%83%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D1%8C-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8E/hl/wrapper+thread/index.html

Автор: GoldFinch 1.3.2010, 18:54
Код

class Foo
{
     int __stdcall thread_func(void);

};

Foo foo;

union AllCastingCast
{
    int (__stdcall Foo::*met)();
    int (__stdcall *fn)(void*);
    // тут можно написать static_assert(sizeof(AllCastingCast)==sizeof(void*), "с этим методом фокус не пройдет");
} ptr = { &Foo::thread_func }

CreateThread(0, 0, ptr.fn, &foo, 0, 0);

метод объявляется как stdcall, this - параметр потока

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

Добавлено @ 18:58
Цитата(GoldFinch @  1.3.2010,  18:54 Найти цитируемый пост)
разумеется это работает только для тех случаев, когда указатель на метод класса является указателем на код метода класса, 
т.е. в классе нет виртуальных функций и множественного наследования

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

Добавлено @ 18:59
алсо рекомендую таки использовать boost.thread + boost.bind

Автор: null56 1.3.2010, 19:08
извиняюсь за дубляж, плохо искал значит

спасибо за помощь

Автор: GremlinProg 1.3.2010, 19:42
нет, null56, явно колбеком методы класса передавать нельзя,
т.к. они сильно зависят от конкретных реализаций и класса (как заметил GoldFinch), и компилятора,
лучше смотри в сторону azesmcar и X-3R1, это гораздо читабельнее, корректнее и проще

Автор: null56 1.3.2010, 20:45
GremlinProg
я сделал через статику и через this, а параметры передал через сам объект... очень удобно и корректно показалось....
хотя вариант с шаблоном тоже не плохо смотрится....

Вариант GoldFinch интересный, но действительно опасный, выдирать адрес колбека... 

Автор: GoldFinch 1.3.2010, 20:51
если туда в самом деле добавить статик_ассерт (например BOOST_STATIC_ASSERT  или static_assert в C+0x),
то все будет безопасно, код будет компилиться для тех методов с которыми все будет работать,
а для тех методов с которыми этот код работать не будет компилятор выдаст ошибку.

Автор: GremlinProg 1.3.2010, 20:57
Цитата(GoldFinch @  1.3.2010,  22:51 Найти цитируемый пост)
если туда в самом деле добавить статик_ассерт (например BOOST_STATIC_ASSERT  или static_assert в C+0x),то все будет безопасно

о_О, чего сказал?

Автор: azesmcar 1.3.2010, 21:05
Цитата(GoldFinch @  1.3.2010,  20:51 Найти цитируемый пост)
если туда в самом деле добавить статик_ассерт (например BOOST_STATIC_ASSERT  или static_assert в C+0x),
то все будет безопасно, код будет компилиться для тех методов с которыми все будет работать,
а для тех методов с которыми этот код работать не будет компилятор выдаст ошибку. 

 smile 

Автор: GoldFinch 1.3.2010, 21:11
GremlinProg, 
я сказал, что единственный источник проблем в предложенном мной коде, 
это то что не всегда указатель на член класса реализуется как обычный указатель.

однако это можно проверить, сравнив размеры указателя на метод и обычного указателя (void*)
тот указатель на член класса, который не является обычным указателем, содержит дополнительную информацию, по этому его размер больше, чем размер обычного указателя

по этому можно написать 
Код

    union AllCastingCast
    {
       int (Foo::*met)();
       int (*fn)(void*);
    } ptr = { &Foo::thread_func }
    static_assert(sizeof(ptr)==sizeof(void*), "с этим методом код работать не будет, т.к. указатель на него не является обычным указателем");


Добавлено @ 21:15
те кто не использует компилятор с поддержкой C++0x могут использовать
Код

#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(sizeof(ptr)==sizeof(void*));


Добавлено @ 21:20
впрочем счя проверил этот код на g++ 4.1.2  (codepad.org), он не работает (т.е. срабатывает ассерт).
что же, это означает, что тем кто пишет код под Windows на gcc - неповезло.

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

Автор: GremlinProg 1.3.2010, 21:20
Цитата(GoldFinch @  1.3.2010,  23:11 Найти цитируемый пост)
тот указатель на член класса, который не является обычным указателем, содержит дополнительную информацию, по этому его размер больше

ну, если бы мы разбирали конкретную реализацию компилятора, например как у Delphi, то да, могло бы прокатить,
только у Delphi нет таких богатых инструментов compile-time, чтобы такое там можно было использовать, так что - нет, это не вариант для си/си++

Добавлено через 3 минуты и 50 секунд
си просто не хранит this рядом с указателем на метод принципиально

Автор: GoldFinch 1.3.2010, 21:26
GremlinProg, говоря о винде, мы скорее всего говорим о MSVC.

хотя конечно есть Borland C++ и есть Intel C++ compiler, и есть Clang (o_O) и много чего еще.
разумеется этот код может не работать ни на чем кроме MSVC.
однако это не повод не использовать этот код тем кто всегда юзает MSVC

в любом случае - имхо лучшее решение это boost.thread

Добавлено @ 21:28
Цитата(GremlinProg @  1.3.2010,  21:20 Найти цитируемый пост)
си просто не хранит this рядом с указателем на метод принципиально 

не понял.

this передается в метод отдельно, как 1й аргумент функции потока, потому что там указано что метод использует stdcall

Автор: GremlinProg 1.3.2010, 21:34

ничего не имею против g++, delphi и borland в целом,
я просто говорю, что для си, как такового, это решение не подходит,
т.к. си принципиально не хранит ни каких дополнительных данных рядом с указателями,
даже теми, которые выступают в роли членов класса

Автор: GoldFinch 1.3.2010, 21:48
GremlinProg, помоему тема катится непонятно куда, пора бы заканчивать.
есть стандарт С++, в нем написано что указатель на член класса - это не обычный указатель и его представление в памяти зависит от реализации.

Цитата("ISO/IEC 14882-2003")

примечание к 4.11. p2:
__________________
52) (...) Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of
such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

8.3.3 p3:
The type “pointer to member” is distinct from the type “pointer”,
that is, a pointer to member is declared only by the pointer to member declarator syntax, and never by the
pointer declarator syntax.


также известно, как именно реализованы указатели на функции-члены классов в MSVC:
за исключением особых случаев, это обычные указатели, которые можно преобразовывать в другие указатели

Автор: GremlinProg 1.3.2010, 22:05
Цитата(GoldFinch @  1.3.2010,  23:48 Найти цитируемый пост)
есть стандарт С++, в нем написано что указатель на член класса - это не обычный указатель и его представление в памяти зависит от реализации.

вообще-то тут
Цитата(GoldFinch @  1.3.2010,  23:48 Найти цитируемый пост)
Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

написано совсем другое: указатель на член класса - это не указатель на объект или на функцию... :))

что естественно не означает, что "его представление в памяти зависит от реализации", хотя в принципе не отрицает,

просто делегирование, которое обычно осуществляется этим самым this рядом с указателем на метод заложено в самой семантике языка, что позволяет не держать его именно рядом :)))

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

Автор: GoldFinch 1.3.2010, 22:17
GremlinProg, какое еще делегирование в С++ ?
что значит "this рядом с указателем на метод"?
напиши подробнее.

Автор: GremlinProg 1.3.2010, 22:42
создай новую тему в соответствующем разделе, или воспользуйся поиском: http://forum.vingrad.ru/act-Search/CODE/show/searchid-ea49d606754b2ec12df7c223c71bbbe8/search_in-posts/result_type/topics/flag/search/highlite/%25D0%25B4%25D0%25B5%25D0%25BB%25D0%25B5%25D0%25B3%25D0%25B8%25D1%2580%25D0%25BE%25D0%25B2%25D0%25B0%25D0%25BD%25D0%25B8%25D0%25B5/index.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)