Я не помню деталей Boost.Thread, но общая идея примерно такая:
class thread_function_base
{
public:
virtual ~thread_function_base(void) {}
virtual void run(void) = 0;
};
template <typename Func>
class thread_function_0 : public thread_function_base
{
public:
thread_function_0(const Func& pFunc) :
mFunc(pFunc)
{}
void run(void)
{
mFunc();
}
private:
Func mFunc;
};
template <typename Func, typename A0>
class thread_function_1 : public thread_function_base
{
public:
thread_function_1(const Func& pFunc, const A0& pA0) :
mFunc(pFunc),
mA0(pA0)
{}
void run(void)
{
mFunc(mA0);
}
private:
Func mFunc;
A0 mA0;
};
// and so on to some limit, either
// generated either by hand (yuck), by
// Boost.PP (phew), or by C++0x's
// variadic templates (yay, no limit either)
class thread
{
public:
template <typename Func>
thread(const Func& pFunc)
{
std::auto_ptr<thread_function_base>
threadFunc(new thread_function_0<Func>(pFunc));
create_thread(threadFunc);
}
template <typename Func, typename A0>
thread(const Func& pFunc, const A0& pA0)
{
std::auto_ptr<thread_function_base>
threadFunc(new thread_function_1<Func, A0>(pFunc, pA0));
create_thread(threadFunc);
}
// again, needs to be generated somehow
private:
// noncopyable
thread(const thread&);
thread& operator=(const thread&);
// signature needs to match implementations expectations:
static void thread_function(void* pUserData)
{
std::auto_ptr<thread_function_base>
pFunc(static_cast<thread_function_base*>(pUserData));
// (A)
pFunc->run();
}
void create_thread(std::auto_ptr<thread_function_base>& pThreadFunc)
{
// again, implementation specific function:
if (create_thread(&thread_function, pThreadFunc.get(), ...))
{
// failed, do something (and return),
// auto_ptr in constructor will free resources
return;
}
// thread was created, so it now owns that resource
pThreadFunc.release();
// (B)
}
};
По сути, все, что нужно для вызова потока, копируется в некоторый динамически размещенный контейнер, указатель на этот динамический контейнер передается в функцию потока (тривиально), затем право собственности передается извне потока внутрь.
Вы можете сделать вещи более безопасными, упаковав не только thread_function_base
в пользовательские данные, но также и (специфичный для реализации) дескриптор сигнала. Функция многопоточности будет блокироваться на (A)
, пока сигнал не будет поднят на (B)
, что указывает на то, что основной поток предоставил рабочему потоку полное владение ресурсами. (И оттуда это auto_ptr
в конечном счете удалит это.)
И так далее, делая его более изощренным.