线程中指向这个*的指针
Pointer to this* in thread
我有一个类和一个库(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);
我的类方法工作得很好,但我需要改变当前类的一些字段(如'状态')或者)我有一个想法传递一个指针到当前类的线程,并在线程函数改变类字段。Some kind:
sys_thread_new("main_thread",(lwip_thread_fn)&this->main_thread, (void*)this,
DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
Then in 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;
这里有两个问题:如果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);
如果必须将指针强制转换为函数来获取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
。这是一个很好的主意抓住它在一个doStartThread
中的std::unique_ptr
,尽管您仍然想要在这个函数中捕获异常,否则它们会终止这个过程。不要忘记delete
ifpthread_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
对象本身,而不是指向的任何东西
- 如何检索指向在单独线程上运行的函数的移动指针?
- 如何将'this'指针传递给C++ WinAPI 线程?
- 从子线程访问指针
- 将字符串指针传递到C++和Xcode 11.1中不同线程上运行的函数
- 通过std::shared_ptr使用Rcpp和RcppParallel的线程安全函数指针
- 在多线程函数中返回共享的常量指针会导致计时问题吗?
- 线程中的成员函数指针
- 如何安全地终止线程?(使用指针)C++
- 指向成员对象的指针 - 中断线程
- 是否可以访问非线程安全容器内指针指向的值(线程安全映射中的条目)?
- 如何抓取指向Qt中弹出对话框的指针,该对话框阻止了QTest中的UI线程
- 将指针传递到另一个线程的正确方法
- CPP:如何使用需要指针的方法创建线程
- 启动线程会导致指针初始化时出现分段错误
- 是否访问指针元组和互斥锁线程安全
- 在容器中存储指向对象的指针时的线程安全
- 为什么当我在构造函数中创建线程时,实例化对象和对象的指针的行为不同
- 指针在不同的线程中获得错误的价值
- C++ 线程函数指针实现返回错误无效使用非静态成员函数
- 指向对象初始化的静态指针——线程安全