【问题标题】:Does memory stay allocated when a C++ thread exits?当 C++ 线程退出时,内存是否保持分配状态?
【发布时间】:2009-04-07 07:51:06
【问题描述】:

我在 Linux 上使用 pthread 库。

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

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

这是因为线程无法从其他线程访问内存,还是因为一旦线程 A 停止,内存就会被取消分配?或者两者都不是;这很可能是我的代码中的一个错误,但我只是想排除这种情况......

更新:

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

【问题讨论】:

  • 什么样的字符串?您是否在定义字符串的范围以外的范围内打印?
  • std::string - 尝试了堆栈和堆内存,在这两种情况下都是相同的问题,它看起来像我的代码中的一个错误。这是我第一次使用 C++ 线程,所以我可能犯了一个愚蠢的错误 :)

标签: c++ multithreading pthreads


【解决方案1】:

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

【讨论】:

  • 我很确定这是我的问题......我已经发布了这个问题的答案,我认为是导致问题的原因!谢谢。
【解决方案2】:

虽然每个线程都有它“自己的”内存(即——它自己的堆空间)……内存就是内存。启动一个线程不会对另一个线程的内存做任何事情。线程 B 如何获取线程 A 中字符串的指针?

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

【讨论】:

  • 对不起,细节很粗略......我觉得这个应用程序太复杂了,不能发布一个例子(因为这很可能是错误的),无论如何,我已经用解决方案!谢谢。
【解决方案3】:

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

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

希望对你有帮助

【讨论】:

    【解决方案4】:

    虽然你的“正确方法”有效,但它对你原来的问题的解决方法太多了。

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

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

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

    而且这两种解决方案都缺乏对地图或地图项目的锁定,这是一个完全不同的问题。

    【讨论】:

    • 刚刚根据你的更新了我的答案,谢谢。我指的是 &mt1 作为参考,这是正确的,还是仍然是一个指针?
    【解决方案5】:

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

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

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

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

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

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

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

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

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

        诠释我; // 两个函数范围内的一些变量 无效 f1() { 而(真) { 我++; 我 %= 128000; } } 无效 f2() { 而(真) std::cout

        【讨论】:

          【解决方案8】:

          事实证明,问题是由于内存使用不正确引起的,正如预期的那样。我 99% 确定以下示例是准确的;它几乎是伪代码,所以显然不会编译。

          更新:

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

          错误的方式(带栈内存):

          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;
          }
          

          【讨论】:

          • 在你的第一个实现的 onlyFunctionRunFromThread2() 中写入 "MyType1 &mt1 = myMap[0]" 会解决你的问题。
          猜你喜欢
          • 2020-12-04
          • 2012-08-06
          • 2014-10-23
          • 1970-01-01
          • 1970-01-01
          • 2014-10-28
          • 2020-04-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多