gpt4 book ai didi

c++ - 针对C++静态销毁/构造订单问题的特定于平台的解决方法

转载 作者:行者123 更新时间:2023-11-30 04:29:45 26 4
gpt4 key购买 nike

我正在Windows XP Pro SP 3下使用标准(非托管)C++中的Visual Studio 2008进行开发。

我围绕std::cout创建了一个线程安全的包装器。此包装器对象是用于#定义为cout的宏的直接替代(即同名)。许多代码都使用它。它的行为可能与您预期的差不多:

  • 在构造时,它会创建一个关键部分。
  • 在调用operator <<()的过程中,它锁定关键部分,将要打印的数据传递给cout,最后释放关键部分。
  • 销毁时,它会销毁关键部分。

  • 该包装器位于静态存储中(它是全局的)。像所有此类对象一样,它在main()开始之前进行构造,而在main()退出之后进行破坏。

    在另一个也驻留在静态存储中的对象的析构函数中使用我的包装器是有问题的。由于此类对象的构造/破坏顺序不确定,因此我很可能尝试锁定已破坏的关键部分。我看到的症状是我的程序在尝试锁定时阻塞了(尽管我认为很容易发生任何事情)。

    至于处理这个问题的方法...
  • 我不能在析构函数中做任何事情;具体来说,我会让关键部分继续存在。 C++标准保证cout不会在程序执行期间死亡,这将是使我的包装器表现出类似行为的最佳尝试。当然,我的包装器在其空的析构函数运行后将“正式”死亡,但是(我讨厌这个词)它的功能可能与析构函数运行之前一样。在我的平台上,情况确实如此。但是,我的天哪是丑陋的,不可携带的,并且将来可能会损坏...
  • 我将关键部分(而不是对cout的流引用)保存在pimpl中。通过pimpl访问所有关键节之前,都要检查pimpl是否为空。碰巧我在析构函数中调用pimpl后忘记将pimpl设置为0。如果我将其设置为0(无论如何我都应该这样做),则在销毁其包装后调用我的包装器不会对关键部分产生任何影响,但仍会将要打印的数据传递给cout。在我的平台上,这似乎也可行。再次丑陋...
  • 我可以告诉我的队友在main()退出后不要使用我的包装器。不幸的是,其空气动力学将与坦克的空气动力学相同。

  • 问题:

    *问题1 *
    对于情况1,如果我不破坏关键部分,则操作系统中的关键部分将发生资源泄漏。我的程序完全退出后,这种泄漏会继续存在吗?如果不是这样,情况1将变得更可行。

    *问题2 *
    对于情况1和2,有人知道在空的析构函数运行后,是否确实可以在我的特定平台上安全地继续使用包装器吗?看来可以,但是我想看看是否有人对我的平台在这种情况下的行为有任何明确的了解...

    *问题3 *
    我的建议显然是不完善的,但我看不出真正正确的解决方案。外面有人知道这个问题的正确解决方案吗?

    旁注:当然,如果我尝试在另一个也位于静态存储中的对象的构造函数中使用包装器,则可能会出现相反的问题。在这种情况下,我可能会尝试锁定尚未创建的关键部分。我想使用“首次使用时构造”惯用语来解决此问题,但这需要对使用我的包装器的所有代码进行语法更改。这将需要放弃使用<<操作符的自然性。而且有太多代码需要修改。因此,这不是可行的选择。对于这个问题的一半,我的想法还不算很深,但是我会问一个问题,这可能是解决问题的另一种不完美方式的一部分...

    *问题4 *
    正如我所说的,我的包装器位于静态存储中(它是全局的),并且具有pimpl(激素问题:))。我的印象是,静态存储器中变量的原始字节在加载时设置为0(除非代码中的初始化不同)。这意味着包装器构造之前,包装器的pimpl的值为0。它是否正确?

    谢谢,
    戴夫

    最佳答案

    第一件事是,我将重新考虑您在做什么。您不能仅通过向每个操作添加锁定来创建线程安全接口(interface)。接口(interface)中必须设计线程安全性。您所建议的替换数量减少的问题在于,它将使每个操作线程安全(我认为它们已经安全了),但这不能避免不必要的交错。

    考虑两个执行cout << "Hi" << endl;的线程,锁定每个操作并不排除将“HiHi \ n \ n”作为输出,并且使用操纵器会使事情复杂化,其中一个线程可能更改要打印的下一个值的格式,而另一个线程可能会触发下一次写入,在这种情况下,两种格式将是错误的。

    关于您提出的特定问题,您可以考虑使用标准库对iostream采取的相同方法:

    而不是将对象创建为全局对象,而是创建一个辅助类型,该辅助类型将对类型的实例数进行引用计数。构造函数将检查对象是否是要创建的对象的第一个类型,并初始化线程安全包装器。最后要销毁的对象将破坏您的包装器。下一个难题是在 header 中创建该类型的全局静态变量,而该 header 又包括iostreams header 。最后一个难题是用户应该包括 header 而不是iostream。

    关于c++ - 针对C++静态销毁/构造订单问题的特定于平台的解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9122900/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com