C++ 在不同位置删除指针会导致不同的行为(崩溃或不崩溃)

C++ 在不同位置删除指针会导致不同的行为(崩溃或不崩溃),c++,multithreading,pointers,memory-management,heap,C++,Multithreading,Pointers,Memory Management,Heap,这一问题是一个改进的问题,其方向与预期的不同 在我的多线程应用程序中,主线程创建并存储参数: typedef struct { int parameter1; double parameter2; float* parameter3; } jobParams; typedef struct { int ID; void* params; } jobData; std::vector<jobData> jobs; // main threa

这一问题是一个改进的问题,其方向与预期的不同

在我的多线程应用程序中,主线程创建并存储参数:

typedef struct {
    int parameter1;
    double parameter2;
    float* parameter3;
} jobParams;

typedef struct {
    int ID;
    void* params;
} jobData;

std::vector<jobData> jobs;

// main thread
for (int i = 0; i < nbJobs; ++i) {
    jobParams* p = new jobParams;
    // fill and store params

    jobData data;
    data.ID = i;
    data.params = p;

    jobs.push_back(data);
}

// start threads and wait for their execution

// delete parameters
for (int i = 0; i < jobs.size(); ++i) {
    delete jobs[i].params;
}
整个过程将void*作为参数,以便能够使用任何结构作为参数,但job函数会将其转换回正确的结构:

void* jobFunction(void* param) {
    jobParams* params = (jobParams*) param;
    // do stuff
    return 0;
}
我的问题是:如果我在
jobFunction()
的末尾
delete params
,它会正常工作。但是,我希望由线程或主线程负责删除,这样我就不必记住删除我编写的每个
jobFunction()
的参数

如果我在treads中调用
jobFunction()
之后,甚至在确保所有线程都已完成(因此不再需要参数)之后,在主线程中尝试
删除参数,则会出现堆损坏错误:

HEAP[prog]:为RtlFreeHeap(02E90000,03C2EE38)指定的地址无效

我使用的是Visual Studio 2008 Pro,因此无法使用valgrind或其他*nix工具进行调试。“子线程”对主线程的所有访问都是使用互斥锁同步的,因此问题不在于我删除了相同的参数两次

事实上,通过使用VS memory viewer,我知道jobParams指针指向的内存在jobFunction()的结尾和我尝试删除它的位置之间(在主线程或“子线程”中)不会改变


我添加了这两种结构的定义,以及我想要删除参数的方式。

这种错误通常意味着您在某个地方有数据竞争。main->getNextParams()即使一次被多个线程调用,也能做正确的事情吗?如果两个参数都相同,你就可以得到一个双自由度

而且,代替

jobFunction(jobData->ID, jobData->params);
你可能是说

jobFunction(job->ID, job->params);

这种错误通常意味着你在某个地方有一场数据竞赛。main->getNextParams()即使一次被多个线程调用,也能做正确的事情吗?如果两个参数都相同,你就可以得到一个双自由度

而且,代替

jobFunction(jobData->ID, jobData->params);
你可能是说

jobFunction(job->ID, job->params);

要调试它,您可以向
jobParams
类添加
deleted
成员,并将其设置为
true
,而不是实际删除对象。然后请参见检查
jobParams
的每个方法中的
deleted
标志,如果为真,则抛出异常。然后查看引发异常的位置。

要调试异常,可以向
jobParams
类添加
deleted
成员,并将其设置为
true
,而不是实际删除对象。然后请参见检查
jobParams
的每个方法中的
deleted
标志,如果为真,则抛出异常。然后查看抛出异常的位置。

正如我所想。。你能试试吗

for (int i = 0; i < jobs.size(); ++i) {
    delete (jobParams*)jobs[i].params;
}
for(int i=0;i
新建类型jobParams,然后删除void*可能是问题的原因


是否有任何理由将参数存储为jobData中的void*?我认为,如果您希望拥有不同类型的JobParam,那么您应该使用继承层次结构,而不是像一个想法那样盲目地将其转换为空*

。。你能试试吗

for (int i = 0; i < jobs.size(); ++i) {
    delete (jobParams*)jobs[i].params;
}
for(int i=0;i
新建类型jobParams,然后删除void*可能是问题的原因


是否有任何理由将参数存储为jobData中的void*?我认为,如果您希望拥有不同类型的jobParams,那么您应该使用继承层次结构,而不是盲目地将其转换为空*

我们可以看看如何删除job->params吗?按照你的建议去做,你不应该有任何问题(我自己也从来没有做过类似的事情)。我们还可以看到jobData类/结构定义吗?我同时添加了这两个。如果我只是简单地删除jobFunction()中的参数,它就可以工作,但我希望在主线程中这样做,如图所示。既然您说如果您尝试从主线程中删除,问题就会发生,那么连接代码中可能有一些bug。可以在问题文本中显示一些代码吗?您所说的连接代码是什么意思?我等待线程完成的代码?是的,这就是我的意思。我们可以看看如何删除作业->参数吗?按照你的建议去做,你不应该有任何问题(我自己也从来没有做过类似的事情)。我们还可以看到jobData类/结构定义吗?我同时添加了这两个。如果我只是简单地删除jobFunction()中的参数,它就可以工作,但我希望在主线程中这样做,如图所示。既然您说如果您尝试从主线程中删除,问题就会发生,那么连接代码中可能有一些bug。可以在问题文本中显示一些代码吗?您所说的连接代码是什么意思?我等待线程完成的代码?是的,这就是我的意思。是的,getNextParams()是线程安全的。我使用互斥来确保不会两次返回相同的参数。无论如何,如果是这样的问题,删除jobFunction()中的参数也不会起作用。好的。我认为这是值得检查的,因为基于“如果问题是X,那么我的程序应该更早崩溃”的调试有时会让我失败,因为“未定义的行为”有时只是做了正确的事情:所以据我所知,双重删除有时可能有效,有时无效,原因不仅仅是像我这样的凡人。是的,我完全同意。在查看其他任何地方之前,我仔细检查了这种同步问题。是的,getNextParams()是线程安全的。我使用互斥来确保不会两次返回相同的参数。无论如何,如果是这样的问题,删除jobFunction()中的参数也不会起作用。好的。我觉得值得一看,