C++ 分离线程的参数存在问题

C++ 分离线程的参数存在问题,c++,multithreading,pointers,pthreads,condition-variable,C++,Multithreading,Pointers,Pthreads,Condition Variable,我正在做一个学校的项目(虚拟内存模拟),我们应该使用分离的线程。我们可以使用的东西也有其他限制,但我稍后会提到这一点。问题是,当我给pthread_create函数最后一个参数(void*)时,创建的线程被分离,pthread_create调用的函数将接收该参数,但是由于线程被分离,我调用pthread_create的函数一完成,原始参数就会被删除,这意味着被调用函数中的参数不再有效,因此会出现分段错误等。。这是代码的一部分(不能全部发布,太大了): 在这个函数中,我最终调用了有指针指向的函数。

我正在做一个学校的项目(虚拟内存模拟),我们应该使用分离的线程。我们可以使用的东西也有其他限制,但我稍后会提到这一点。问题是,当我给pthread_create函数最后一个参数(void*)时,创建的线程被分离,pthread_create调用的函数将接收该参数,但是由于线程被分离,我调用pthread_create的函数一完成,原始参数就会被删除,这意味着被调用函数中的参数不再有效,因此会出现分段错误等。。这是代码的一部分(不能全部发布,太大了):

在这个函数中,我最终调用了有指针指向的函数。正如您所猜测的,当“NewProcess”函数结束时,参数变得无效,因此我试图通过添加一个条件变量来克服这一点,并以某种方式复制我已经(尚未找到解决方案)的参数,然后让“NewProcess”函数结束。但是这个项目有一定的局限性。函数“NewProcess”被多次调用,线程应该同时运行(我尝试在调用entryPoint后向条件变量发送信号,结果成功),因此我无法完成一个线程,然后再执行下一个线程。第一个函数的参数“void*processArg”最初是某个对象类型,无法从上述两个函数访问该类型


所以,有谁能给我一个建议,如何复制参数,这样我就不会有分离错误了?

这个问题非常简单,它涉及到对象的生命周期和所有权

您正在将'args'的地址传递给线程,但是'args'是在堆栈上创建的,并且在线程启动后不久就超出范围

这样做:

// note: The ThrArgs constructor should take ownership of processArg
std::unique_ptr<ThrArgs> args (new ThrArgs(entryPoint, (void *) processArg, ccpu));
if (pthread_create(&thread, NULL, StartWork, (void *) args.get())) {
    args.release();
    // ownership of the pointer now belongs to the thread
    return 0;
}
//注意:Thargs构造函数应该拥有processArg的所有权
std::unique_ptr args(新ThrArgs(entryPoint,(void*)processArg,ccpu));
if(pthread_create(&thread,NULL,StartWork,(void*)args.get()){
args.release();
//指针的所有权现在属于线程
返回0;
}
然后在线程函数中:

void* CProcManager::StartWork(void* arguments) {
    std::unique_ptr<ThrArgs> args (reinterpret_cast<ThrArgs*>(arguments)); 

    // now use args as a pointer

    ....


    // the arguments will be deleted here
    return 0;
}
void*CProcManager::StartWork(void*arguments){
std::unique_ptr args(重新解释强制转换(参数));
//现在使用args作为指针
....
//参数将在此处删除
返回0;
}

有两种解决方案。最简单的方法通常只是分配 动态显示参数:在
NewProcess
中:

ThrArgs* args = new ThrArgs( entryPoint, processArg, ccpu );
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if (!results) {
    delete args;
}
(您可以在此处使用
std::unique_ptr
std::auto_ptr
) 那么,在这种情况下,除非
pthread\u创建
成功!)

另一种方法是在上创建一个条件变量 一个布尔值,然后在离开函数之前等待它,然后复制 输入参数,然后在新线程中设置布尔值:in
NewProcess

pthread_mutex_lock( &theMutex );
freeToContinue = false;
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if ( results ) {
    while ( !freeToContinue ) {
        pthread_cond_wait( &theCond, &theMutex );
    }
    pthread_mutex_unlock( &theMutex );
}
return results;
StartWork
(传递给
pthread\u create的函数)
必须是
外部“C”
,因此不能是成员):

void*StartWork(void*arguments)
{
pthread_mutex_lock(&theMutex);
Thargs args=*静态_转换(参数);
freeToContinue=真;
pthread_cond_广播(&theCond);
pthread_mutex_unlock(&theMutex);
//  ...
}
(显然,我在这里漏掉了很多错误检查。)

无论哪种方式:你可能需要做一些类似的事情
processArg
参数,因为它的生存期由 打电话的人


您不需要所有的强制转换来
void*

也不需要在堆栈上分配参数,您就没事了。当然,如果
pthread\u create
失败,这会泄漏内存。当您使用智能指针时,请始终推迟
发布
,直到您验证C函数已成功。这是一个公平点。我会修改代码-好了,修好了。是的。否则,这就是我通常使用的解决方案(不过,这主要是因为我的“对象”是多态的,无论如何都不能在堆栈上分配)。另一方面,Boost threads使用了我在回答中介绍的另一种解决方案,这也是C++11中采用的解决方案。当然,如果线程由于
pthread\u exit
pthread\u cancel
而终止,那么智能指针在子线程中也没有帮助。通过抛出异常,捕获异常并在
StartWork
函数中返回,可以轻松避免
pthread\u退出。对于
pthread_cancel
,您必须注册一个清理例程,该例程将执行类似
delete args.release()的操作
(因为您不知道是否将调用
args
的析构函数)。感谢您的建议,但是我们不允许在此项目中使用unique\u ptr。但我很高兴现在我知道了如何使用它:)谢谢,我觉得很愚蠢,因为我没有意识到我可以使用动态分配的变量。但至少我解决了这个问题:D
ThrArgs* args = new ThrArgs( entryPoint, processArg, ccpu );
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if (!results) {
    delete args;
}
pthread_mutex_lock( &theMutex );
freeToContinue = false;
bool results = pthread_create( &thread, NULL, StartWork, args ) == 0;
if ( results ) {
    while ( !freeToContinue ) {
        pthread_cond_wait( &theCond, &theMutex );
    }
    pthread_mutex_unlock( &theMutex );
}
return results;
void* StartWork( void* arguments )
{
    pthread_mutex_lock( &theMutex );
    ThrArgs args = *static_cast<ThrArgs*>( arguments );
    freeToContinue = true;
    pthread_cond_broadcast( &theCond );
    pthread_mutex_unlock( &theMutex );
    //  ...
}