Использование boost-потока и нестатической функции класса
Итак, я провел некоторое исследование и обнаружил, что вы можете создать объект boost:: thread и начать с нестатической функции класса с помощью "this" и boost:: bind и т.д. Это действительно не имеют для меня большой смысл, и все примеры, которые я смог найти, имели объект boost:: thread, запущенный в том же классе, что и функция, с которой он начинался, поэтому это можно было бы использовать. Тем не менее, я запускаю поток в другом классе, поэтому, боюсь, используя "this", я буду говорить, что "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);
};
Это не весь источник, но я думаю, что моя проблема здесь где-то, я знаю, что мне приходится иметь дело с "this", но я не уверен, как это сделать. Я мог бы использовать статическую функцию, но я действительно не хотел, чтобы мои переменные были статическими.
Спасибо.
Кроме того, есть ли какой-либо очень хороший ресурс для использования каких-либо ускорительных библиотек? Их документация на веб-сайте кажется хорошей, но над моей головой.
Ответы
Ответ 1
Ключевое слово 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));
}
Если функция-член является статической или просто является регулярной (не-членной) функцией, вам вообще не нужен указатель экземпляра. Вы просто сделали бы:
boost::thread* thr = new boost::thread(some_regular_function);
Ответ 2
Как уже упоминалось, когда вы хотите вызвать метод объекта в новом потоке, вы должны указать адрес этого объекта. Но вам не нужно вызывать 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
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;
};
Ответ 4
В таких случаях полезно рассматривать нестатические функции-члены как свободные функции, которые принимают this
как первый параметр, например, в вашем случае void MainThreadFunc(Main* this)
.
boost::thread
принимает нулевой функтор, поэтому вам нужно передать ему нулевой функтор, который содержит ссылку на экземпляр GUIMain
и вызывает GUIMain->MainThreadFunc
, который, как я объяснил выше, будет чем-то вроде MainThreadFunc(GUIMain)
,
Boost (и теперь также С++ с TR1) предоставляет помощники для создания таких функторов, а именно boost::bind
(или, альтернативно, boost::lambda::bind
). Выражение boost::bind(f, arg1, arg2, ...)
означает "возвращает нулевой функтор, который вызывает f(arg1, arg2, ...)
".
Тем не менее, вы можете использовать следующее выражение для создания потока:
GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain))
Ответ 5
Если ваш объект является функтором, то есть имеет 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;
}