c++:如何定义类方法作为线程的启动例程(使用pthread库)
C++: how to define a class method as a start routine to thread (with pthread library)
我有一个基类和派生类。它们有一个虚函数——虚void action()我怎么能把它传递给*pthread_create()*函数?
示例(错误):
class Base{
protected:
pthread_t tid;
public:
virtual void* action() = 0;
};
class Derived : public Base{
void* action();
Derived(){
pthread_create(&tid, NULL, &action, NULL);
}
};
也许应该是静态的?我尝试了很多组合,但无法找到解决方案。
几个月前我在做我的高级设计项目时遇到了这个问题。它需要对c++的基本机制有一定的了解。
根本问题是指向函数的指针不同于指向成员函数的指针。这是因为成员函数有一个隐式的第一个参数this
。
从man
页:
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg);
线程入口点为void* (*)(void*)
。函数Base::action
的类型是void* (Base::*)()
。这个丑陋的类型声明的Base::
部分表示this
的类型。类型差异是编译器不接受你的代码的原因。
有两件事我们需要修复使这个工作。不能使用成员函数,因为指向成员函数的指针不会将this
绑定到实例。我们还需要一个void*
类型的参数。值得庆幸的是,这两个修复是齐头并进的,因为解决方案是显式地传递this
。
class Base {
public:
virtual void* action() = 0;
protected:
pthread_t tid;
friend void* do_action(void* arg) {
return static_cast<Base*>(arg)->action();
}
};
class Derived : public Base {
public:
Derived() {
// This should be moved out of the constructor because this
// may (will?) be accessed before the constructor has finished.
// Because action is virtual, you can move this to a new member
// function of Base. This also means tid can be private.
pthread_create(&tid, NULL, &do_action, this);
}
virtual void* action();
};
Edit:哎呀,如果tid
是protected
或private
,那么do_action
需要是friend
你必须有一个函数,它接受一个void指针传递给pthread_create
。我自己写这个函数,作为一个函数,它接受一个指向Base
的指针(Derived
也可以工作),然后调用参数的action
函数。然后,您可以创建一个线程来运行该函数并接收this
作为参数:
void *f(void *param)
{
Base* b = (Base *)param;
return b->action();
}
class Derived : public Base{
void* action();
Derived() {
pthread_create(&tid, NULL, f, this);
}
};
确实必须是静态的。您还需要将您的对象作为参数传递给pthread_create:
void *Base::static_action(void *v)
{
((Base*)v)->action();
return NULL;
}
pthread_create(&tid, NULL, &Base::static_action, myObject);
我通常做类似的事情,我将让您填写其他细节(错误处理,锁定等):
Start方法:
bool pthreadBase::start()
{
return pthread_create(&threadID, NULL, &execute,this);
}
静态void* Execute方法:
void *pthreadBase::execute(void *t)
{
reinterpret_cast<pthreadBase *> (t)->processLoop();
return NULL;
}
之后,你可以创建一个名为processLoop的虚拟方法,它将作为线程的入口点。
下面是一个简单的实现(未测试):
class theThread: public pthreadBase
{
public:
theThread(SharedMemoryStructure *SharedMemory)
{
_Running = start();
_Shared = SharedMemory;
}
~theThread()
{
stop(); //Just do a join or something
_Running = false;
}
private:
void processLoop()
{
while(_Shared->someQuitFlag() == false)
{
/*Do Work*/
}
}
private:
bool _Running;
SharedmemoryStructure *_Shared;
};
将其设置为静态并不能保证一定有效,但实际上至少在大多数实现中是有效的(并且有足够多的人依赖于它,因此我也会对很快看到这种变化感到有点惊讶)。
- 使用 std::string () const 函数启动线程或未来
- 如何创建线程序列以按照启动顺序执行任务?
- 启动类函数作为失去引用的线程
- 重新启动后,线程无法在 while 循环中再次运行
- 如何在C++上启动异步线程
- 计时器是否从另一个线程启动?
- 如何在 MFC 应用程序中启动 ZeroMQ 线程?
- C++ POCO - 如何在不使用 run() 方法的情况下启动线程池上的线程?
- 为什么 pthread_create() 返回 0 但线程从未启动
- 为什么 cuda-gdb 会启动多个线程?
- 对于每个线程,random_device是否以不同的状态启动?
- 线程启动延迟 - 通知所有未唤醒所有线程
- 等待多个线程启动,start() 未捕获
- Qt多线程启动线程错误
- 用信号通知线程启动特定的函数
- C++简单的线程启动问题
- - C++ - 使用计时器线程启动异常,精度毫秒
- 传递字符串作为线程启动例程参数:c++
- 错误:无法从另一个线程启动计时器.使用未声明计时器的QFuture
- QT线程:获取QObject::startTimer:计时器无法从另一个线程启动警告