Использование Boost Thread и нестатической функции класса - PullRequest
44 голосов
/ 03 января 2011

Итак, я провел некоторое исследование и обнаружил, что вы можете создать объект boost :: thread и начать его с нестатической функции класса, используя «this», boost :: bind и т. Д. На самом деле это не так.имеет большой смысл для меня, и во всех примерах, которые я смог найти, объект boost :: thread был запущен в том же классе, что и функция, с которой он начинал, так что это можно использовать.Я, однако, запускаю поток в другом классе, поэтому, боюсь, используя «this», я буду говорить, что «this» принадлежит классу, из которого я создаю поток, а не тому, в котором находится функция (Я, наверное, не прав, мне нужно больше узнать об этом "этом" парне).Вот пример моего источника, с которым у меня проблема:

ANNGUI.h

class ANNGUI
{
private:
    boost::thread *GUIThread;
    Main *GUIMain;
public:
    // Creates the entire GUI and all sub-parts.
    int CreateGUI();
}

ANNGUI.cpp

int ANNGUI::CreateGUI()
{
        GUIMain = new Main();
    GUIThread = new boost::thread(GUIMain->MainThreadFunc);
};

Это не всеисточник, но я думаю, что моя проблема где-то здесь, я знаю, что должен как-то иметь дело с «этим», но я не уверен, как.Я мог бы использовать статическую функцию, но я действительно не хотел делать мои переменные статичными.Спасибо.

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

Ответы [ 5 ]

83 голосов
/ 03 января 2011

Ключевое слово this используется с boost::bind, когда создаваемый объект функции связан с функцией-членом объекта .Функции-члены не могут существовать отдельно от экземпляров, поэтому при создании объекта функтора из функции-члена с boost::bind вам нужен указатель на экземпляр.Именно это и есть ключевое слово this.Если вы используете ключевое слово this в функции-члене класса, вы получите указатель на текущий экземпляр этого класса.

Если бы вы вызывали bind из снаружи функция-член класса, вы можете сказать что-то вроде:

int main()
{
  Foo f;
  boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, &f));
}

Здесь мы используем Foo :: some_function в качестве нашей функции потока.Но мы не можем использовать this, потому что мы звоним bind с main.Но то же самое может быть достигнуто с помощью this, если мы вызовем bind из функции-члена Foo, например:

void Foo::func1()
{
  boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, this));
}

Если функция-член является статической или просто обычнойnon-member), тогда вам вообще не нужен указатель экземпляра.Вы бы просто сделали:

boost::thread* thr = new boost::thread(some_regular_function);
40 голосов
/ 27 мая 2011

Как уже упоминалось, когда вы хотите вызвать метод объекта в новом потоке, вы должны указать адрес этого объекта.Но вам не нужно вызывать boost::bind, вы можете использовать перегруженный конструктор boost::thread следующим образом:

GUIThread = new boost::thread(&Main::MainThreadFunc, GUIMain);

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

t = new boost::thread(&myclass::compute, this);

Если у метода есть параметры, вы можете указать их после второго аргумента, например:

t = new boost::thread(&myclass::compute, this, p1, p2);
3 голосов
/ 03 января 2011

В подобных случаях полезно рассматривать нестатические функции-члены как свободные функции, которые принимают this в качестве первого параметра, например, в вашем случае void MainThreadFunc(Main* this).

boost::thread принимает нулевой функтор, поэтому вы должны передать ему нулевой функтор, который содержит ссылку на экземпляр GUIMain и вызывает GUIMain->MainThreadFunc, что, как я объяснил выше, будет выглядеть как MainThreadFunc(GUIMain) ,

Boost (а теперь и C ++ с TR1) предоставляет помощники для создания таких функторов, а именно boost::bind (или, альтернативно, boost::lambda::bind). Выражение boost::bind(f, arg1, arg2, ...) означает «вернуть нулевой функтор, который вызывает f(arg1, arg2, ...)».

Тем не менее, вы можете использовать следующее выражение для создания потока:

GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain))
3 голосов
/ 03 января 2011

boost :: bind - ваш друг (хотя иногда он может показывать грубый способ показать это)!

использование GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain));

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

Примерно так:

class GUIMain {
public:
  GUIMain() : m_Member(42) {}

  void MainThreadFunc() {
    // use all members as you would normally do
    std::cout << m_Member << std::endl;
  }

private:
  int m_Member;
};
1 голос
/ 29 июля 2013

Если ваш объект является функтором, т. Е. Имеет operator(), вы можете передать его экземпляр в boost::thread. operator() не обязательно должен быть статическим. Например:

#include <boost/thread.hpp>

struct th {
    void operator()();
};

void th::operator()()
{
    for (;;) {
        // stuff
    }
}

int main()
{
    th t;
    boost::thread my_thread( t ); // takes a copy of t !
    my_thread.join(); // blocks
    return 0;
}
...