Создание потока из метода класса

This post is also available in: Английский

Уже несколько раз приходилось сталкиваться с проблемой невозможности запустить поток из функции, которая является методом класса. Компилятор упрямо возвращает ошибку подобную, приведенной ниже:

error C2664: ‘CreateThread’ : cannot convert parameter 3 from ‘unsigned long (__thiscall CMyClass::*)(void *)’ to ‘unsigned long (__stdcall *)(void *)’

И его понять можно.  Функции требуется адрес статической функции. А, запуская поток с метода класса, в большинстве случаев есть желание, чтобы функция работала как полноценный метод экземпляра класса. Решить проблему помогает «финт ушами» описаный здесь. Некоторые советуют использовать для этого boost. Не считаю, что такая мелочь повод для подключения дополнительной библиотеки.

Какой-то умник добавил исходники решения проблемы на говнокод.ру.  Он определенно просто не в теме.

Комментарии 5

  • Финт ушами более не доступен. Что там было?
    Я обычно в таких случаях функцию дружественной объявляю и аргументом объект — не очень изящно, но работает.

    • Прошу прощения, ссылочку поправил. Если кто не хочет переходить «выдерну» самую суть из поста:
      Вместо метода мы создадим поток со статической функцией. А в качестве данных, передадим указатель на структуру, в которую положим:
      1. Указатель на экземпляр класса.
      2. Указатель на метод класса.
      3. Указатель на действительные данные для метода.
      Когда новый поток запустится, то статическая функция, зная указатель на класс и нужный метод, запустит этот метод в новом потоке.

      Про дружественную функцию, если честно, не понял. Как это поможет? Ведь нужна статическая функция.

      • Я обычно как-то так делаю:

        template
        uintptr_t thread(T fn, unsigned stack_size = 0) {
        struct wrapper {
        static unsigned __stdcall function(void * arg) {
        std::auto_ptr w(reinterpret_cast(arg));
        w->fn();
        return 0;
        }

        explicit wrapper(T fn) : fn(fn)
        {}

        T fn;
        };

        std::auto_ptr w(new wrapper(fn));
        uintptr_t res = _beginthreadex(0, stack_size, &wrapper::function, w.get(), 0, 0);
        if (res)
        w.release();
        return res;
        }

        И в момент создания потока биндом (boost::bind/std::bind1st,2nd) прикручиваю необходимые пар-ры.

Добавить комментарий для cqwerty Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *