我有一个类和一个库(lwip)。由于某些原因,我需要调用库的线程创建功能,如:
/** The only thread function:
* Creates a new thread
* @param name human-readable name for the thread (used for debugging purposes)
* @param thread thread-function
* @param arg parameter passed to 'thread'
* @param stacksize stack size in bytes for the new thread (may be ignored by ports)
* @param prio priority of the new thread (may be ignored by ports) */
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int
stacksize, int prio);
在这个函数中我们调用pthread:
code = pthread_create(&tmp,NULL,(void *(*)(void *)) function, arg);
我的电话如下:
sys_thread_new("main_thread",(lwip_thread_fn)&this->main_thread, NULL,
DEFAULT_THREAD_STACKSIZE,DEFAULT_THREAD_PRIO);
我的类方法工作正常,但我需要更改一些CURRENT类(如'state') 或者)我有一个想法,将指向当前类的指针传递给该线程和线程函数更改类字段。某种:
sys_thread_new("main_thread",(lwip_thread_fn)&this->main_thread, (void*)this,
DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
然后在main_thread中:
void lwip::main_thread(void *arg) {
lwip *p = (lwip*)arg;
p->state = 1;
}
这样的事情。但似乎我做错了什么 -
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6e8e700 (LWP 4985)]
0x0000000000403a75 in lwip::main_thread (this=0x7fffffffe4f0, arg=0x80) at
../src/lwip.cpp:50
50 p->state = 1;
答案 0 :(得分:1)
这里有两个问题:如果main_thread
成员函数是静态成员函数,则使用&lwip::main_thread
传递指向它的指针,不需要任何转换。如果该功能不 static
,则必须将其设为static
。
另一个问题是,如果传递给线程函数的实例(this
)被破坏,则线程函数现在具有指向被破坏对象的指针。注意临时对象或按值传递实例。
如果实际的线程函数不能是static
,您可以使用静态包装函数轻松解决它:
class lwip
{
...
private:
void main_thread() { ... }
static void* main_thread_wrapper(void* arg)
{
reinterpret_cast<lwip*>(arg)->main_thread();
return nullptr;
}
};
...
sys_thread_new("main_thread", &lwip::main_thread_wrapper, this,
DEFAULT_THREAD_STACKSIZE,DEFAULT_THREAD_PRIO);
答案 1 :(得分:0)
如果必须将指针强制转换为要获取的函数
要编译pthread_create
,您有未定义的行为。
如果目标是在不同的线程中调用成员函数,
你需要在extern "C"
函数中包装调用。这个
意味着没有成员,没有模板;在最简单的情况下:
extern "C" void*
startThread( void* p )
{
static_cast<T*>(p)->f();
}
并传递startThread
的地址作为第三个参数和
指向对象的指针为第四个。如果涉及继承,
你必须确保第四个参数的类型相同
在startThread
的演员阵容中,例如:
pthread_create( &tmp, nullptr, &startThread, static_cast<Base*>( pointerToDerived ) );
如果startThread
投放到Base*
。
如果您还需要该函数的参数,则需要传递
指向结构的指针,指向对象的指针和
额外的论点。你还需要确保
这个结构的生命周期就足够了,所以没有风险
访问已经不存在的对象的线程。这个
通常意味着一个额外的条件变量,以确保
调用pthread_create
的线程在之前没有继续
新主题已复制了所有相关数据。 (都
Boost线程和C ++ 11线程为您完成此任务。这只是
如果你需要额外的数据,除了
在新线程中指向对象的指针。)
如果你需要为许多不同的人做这件事,那会很痛苦
类型,如果有问题的类是完全不可能的
一个模板。在这种情况下,一种常见的解决方案是使用
一个Thread
对象,沿着:
class Thread
{
public:
virtual void* run() = 0;
};
和启动功能:
namespace {
extern "C" void*
doStartThread( void* p )
{
return static_cast<Thread*>( p )->run();
}
}
pthread_t
startThread( Thread* thread )
{
pthread_t results;
if ( pthread_create( &results, nullptr, doStartThread, thread ) != 0 ) {
throw std::runtime_error( "Could not create thread" );
}
}
之后,您继承Thread
,覆盖run
随心所欲地运行(并添加任何其他数据
你可能需要);派生类甚至可以是模板。
同样,Thread
对象的生命周期是一个问题;该
我经常使用的解决方案就是要求它
动态分配,然后在结束时删除它
doStartThread
。抓住它是一个非常好的主意
std::unique_ptr
中的doStartThread
,尽管你仍然想要
捕获此函数中的异常,否则它们会
杀了这个过程。不要忘记delete
if
pthread_create
失败(因为调用者已经过去了
所有权。如果你真的想确定:
namespace {
extern "C" void*
doStartThread( void* p )
{
std::unique_ptr<Thread*> object( static_cast<Thread*>( p ) );
try {
return object->run();
} catch ( ... ) {
return somethingElseToReportTheError;
}
}
}
pthread_t
startThread( std::unique_ptr<Thread> thread )
{
pthread_t results;
if ( pthread_create( &results, nullptr, doStartThread, thread.get() ) != 0 ) {
throw std::runtime_error( "Could not create thread" );
}
thread.release(); // AFTER the call has succeeded!
}
我已经成功地使用了这种技术
应用程序(使用std::auto_ptr
,因为没有
std::unique_ptr
然后);通常,你需要的事实
使用动态分配不是问题,它解决了
终身问题相当不错。 (另一种方法是使用
一个条件变量,阻塞原始线程直到
新线程复制了一切。)
请注意,通过在界面中使用unique_ptr
,您就可以了
有效阻止调用线程进一步访问
线程对象,通过抢夺它指向对象的指针。这个
提供有关螺纹安全性的额外保证。
但当然,这个额外的保证(以及解决方案)
终身问题)仅适用于Thread
对象本身,
并且不它可能指向的任何东西。