Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте Нартов Андрей Евгеньевич, вы писали:
A>>>уточните зачем это надо.
НАЕ>>например, сделать нить (CreateThread()) из нестатической member function
VD>Ну, для этого можно обойтись и вызовом не статической функции из статической или глобальной, а вообще... я как то выпердривался с этим делом. Как сделать это на C++ я не раскопал. На Delpth это делается легко. На Плюсах пришлось выпендриваться с asm-ом.
VD>Общая идея такова — записываем указатель на фунцию и на this экземпляра объекта в структуру.
VD>И эмулируем вызов функции. Вот код:
Можно прекрасно обойтись и без asm'а. Идея в целом такая же. Вот пример того, как можно запустить методы в других потоках используя POSIX API (проверялось на Linux, gcc).
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
template<class T>
struct Launcher {
private:
T *m_pThis; // указатель на объект, чей метод будет вызван
void (T::*m_pMethod)(); // указатель на метод
pthread_mutex_t m_mutex; // дополнительные поля для синхронизации потоков
pthread_cond_t m_condv; // . . .
bool volatile m_bReady; // . . .
// системно-зависимая функция с которой начинается выполнение потока
static void *threadfunc(void *p) {
// достаем указатели на объект и его метод
Launcher<T> *pObj = (Launcher<T> *) p;
T *pThis = pObj->m_pThis;
void (T::*pMethod)() = pObj->m_pMethod;
// говорим главному потоку, что все нормально
pthread_mutex_lock(&pObj->m_mutex);
pObj->m_bReady = true;
pthread_cond_signal(&pObj->m_condv);
pthread_mutex_unlock(&pObj->m_mutex);
// запускаем метод
(pThis->*pMethod)();
return 0;
}
public:
Launcher(T *pThis, void (T::*pMethod)()): m_pThis(pThis), m_pMethod(pMethod) {
pthread_mutex_init(&m_mutex, 0);
pthread_cond_init(&m_condv, 0);
}
~Launcher() {
pthread_cond_destroy(&m_condv);
pthread_mutex_destroy(&m_mutex);
}
void start() {
pthread_t thr;
m_bReady = false;
// запускаем поток, указываем функцию, с которой поток должен начать работу (threadfunc), и параметр для нее (this)
pthread_create(&thr, 0, threadfunc, this);
// ждем сигнала от запущенного потока, для того, чтобы потом можно было удалить объект Launcher из стека,
// будучи уверенным, что запущенному потоку он уже не нужен.
pthread_mutex_lock(&m_mutex);
if(!m_bReady)
pthread_cond_wait(&m_condv, &m_mutex);
pthread_mutex_unlock(&m_mutex);
}
};
template<class T>
void launch(T *pThis, void (T::*pMethod)()) {
Launcher<T> box(pThis, pMethod);
box.start();
}
// пример использования
struct A {
void func() {
printf("%s\n", __PRETTY_FUNCTION__);
}
};
struct B {
void func1() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void func2() {
printf("%s\n", __PRETTY_FUNCTION__);
}
};
int main() {
A a;
B b;
launch(&a, &A::func);
launch(&b, &B::func1);
launch(&b, &B::func2);
usleep(1000);
return 0;
}
Тоже самое можно написать, используя Win32 API. Этот код никак не зависит от того, в каких регистрах что находится и как на низком уровне осуществляется вызов методов и функций.
--
Дмитрий
PS В этом примере потоки создаются joinable и им нужно было бы сделать pthread_join, чтобы не оставались потоки-зомби. Но я не стал этого делать чтобы не перегружать пример особенностями поточной библиотеки.