当C ++线程退出时,内存是否保持分配状态?

时间:2009-04-07 07:51:07

标签: c++ multithreading pthreads

我在Linux上使用pthread库。

我在线程A中分配一个字符串,然后尝试在线程B中打印字符串。但是,该字符串只打印出空(我已经验证它在线程A中有效)。

注意:字符串驻留在一个对象中,我怀疑它可能被清理或重新实例化为空...容器对象不会给我一个seg错误或任何东西,只是所有的值都是空的。 / p>

这是因为线程无法从其他线程访问内存,还是因为线程A停止后内存未被分配?或者它既不是;它很可能是我的代码中的一个错误,但我只想排除它...

更新

原来这是一个内存问题。感谢您的回答,我也answered this my self,如果您同意/不同意,请对我的回答发表评论。

8 个答案:

答案 0 :(得分:9)

与进程不同,线程在进程内共享一个公共内存空间(每个线程都有自己的堆栈,但堆通常是共享的)。因此,当您退出线程时,不会自动释放从共享堆分配的内存。但是,例如,如果您已经在堆栈上分配了一个字符串对象并通过一个简单的指针将其传递到某处,则析构函数将在线程退出时释放内存。

答案 1 :(得分:2)

尽管每个线程都有自己的“内存”内存(即 - 它自己的堆空间)......内存是内存。开始一个线程对另一个线程的内存没有任何作用。线程B如何获得指向线程A中字符串的指针?

您需要提供更多详细信息......您是否将字符串放在堆上?如果它不在堆上,它可能会在线程A死亡时消失...否则你有一个错误...请发布更多!

答案 2 :(得分:1)

是的,内存保持分配状态。

在包含字符串的类的dtor中放置一个断点或一些记录,看看发生了什么。

希望这有帮助

答案 3 :(得分:1)

虽然你的“正确方法”有效,但这对你原来的问题来说太过多了。

以下是您原始问题所需的唯一更改。

void onlyFunctionRunFromThread2()
{
    MyType1 &mt1 = myMap[0];

   ...

以“正确的方式”,你现在有责任释放你用新分配的内存。在您的原始示例中,它是“自动”完成的(可以这么说)。

两种解决方案都没有锁定地图或地图项目,这是一个完全不同的问题。

答案 4 :(得分:0)

线程完成后,其堆栈将被释放。但是,堆内存不是特定于线程的,因此堆上的任何分配都将保留在那里,除非您执行清理。

字符串是否在堆栈上分配?如果是这样,那么线程之间就没有共享字符串,即使两个线程运行相同的代码。

在以下示例中,函数foo由两个线程运行:

void foo( void*)
{
   std::string myString;
   // Do something with your string....
}

线程之间不共享myString。每个线程在自己的堆栈上都有一个字符串对象。

那么,你所指的真实情况是什么?

答案 5 :(得分:0)

访问共享资源(即字符串)时是否使用锁?

答案 6 :(得分:0)

正如已经说过的,线程对你的记忆没有任何作用。 它们没有任何私有内存空间。 它们只是操作系统调度程序的命令 实现2个或更多功能的“并行”执行。 任何可以访问同一个变量的2个函数都可以 这样做,无论它们是否是线程(并排执行)或不(顺序执行)。

线程通常看起来像一些可怕的怪物,但它确实如此 只是给调度程序一个提示来添加额外的执行 指针。

要调试您描述的问题,只需更改一个更基本的问题 两个函数中的变量类型,如int。 你的容器很可能是内部的 更改字符串或其他内容后立即复制数据 类似。

    int i;    // some variable in the scope of both functions

void f1()
{
   while(true)
    {
       i++;
       i %= 128000;
    }
}
void f2()
{
     while(true)
            std::cout 

答案 7 :(得分:0)

事实证明,问题是由于错误使用内存造成的,正如预期的那样。我99%肯定下面的例子是准确的;它几乎是伪代码,显然不会编译。

更新

感谢nusi刚刚添加了第3个解决方案。

错误的方式(使用堆栈内存):

std::map<int, MyType1> myMap;

void firstFunctionRunFromThread1()
{
    MyType1 mt1;
    mt1.Test = "Test 1";
    myMap[0] = mt1;
}

void onlyFunctionRunFromThread2()
{
    MyType1 mt1 = myMap[0];

    // This actually does print "Test 1", so the memory is being accessed.
    std::cout << mt1.Test << endl;

    /* However, because we're using stack memory here, this value is lost
     * when we go back to thread #1. */
    mt1.Test = "Test 2";
}

void secondFunctionFromThread1()
{
    MyType1 mt1 = myMap[0];

    // This will actually print out "Test 1", where "Test 2" is expected!
    std::cout << mt1.Test << endl;
}

复杂,正确的方法(使用堆内存):

另请参阅使用堆栈内存的简单方法。

std::map<int, MyType1> myMap;

void firstFunctionRunFromThread1()
{
    // Use heap memory so the memory stays allocated.
    MyType1 *mt1 = new MyType1();
    mt1->Test = "Test 1";
    myMap[0] = *mt1;
}

void onlyFunctionRunFromThread2()
{
    /* Now, get a pointer to the object; we can't use stack memory
     * here because the values assigned would be lost as soon as 
     * we try and access them from secondFunctionFromThread1() */
    MyType1 *mt1 = &myMap[0];

    // As expected, this prints "Test 1"
    std::cout << mt1->Test << endl;

    /* Now, because we're assigning to memory on the heap, this will
     * stay assigned until the entire application exits, yay! */
    mt1->Test = "Test 2";
}

void secondFunctionFromThread1()
{
    /* Not sure if using heap memory here is neccecary, but we'll do
     * it anwyay just to play on the safe side... let me know if this
     * is pointless... */
    MyType1 *mt1 = &myMap[0];

    // Hurray, this prints "Test 2"!!! :)
    std::cout << mt1->Test << endl;
}

简单,正确的方法(正确使用堆栈内存):

感谢nusi his answer

std::map<int, MyType1> myMap;

void firstFunctionRunFromThread1()
{
    MyType1 mt1;
    mt1.Test = "Test 1";
    myMap[0] = mt1;
}

void onlyFunctionRunFromThread2()
{
    /* Using the & before the variable turns it into a reference, so
     * instead of using stack memory, we use the original memory.
     * NOTE: Is this explanation correct? */
    MyType1 &mt1 = myMap[0];

    // This actually does print "Test 1", so the memory is being accessed.
    std::cout << mt1.Test << endl;

    // We're assigning to the reference, so this works.
    mt1.Test = "Test 2";
}

void secondFunctionFromThread1()
{
    MyType1 mt1 = myMap[0];

    // Prints "Test 1" as expected.
    std::cout << mt1.Test << endl;
}