繁体   English   中英

当在另一个线程上完成工作时,有没有办法保护智能指针在一个线程上被释放?

[英]Is there a way to protect a smart pointer from being deallocated on one thread, when work is being done on another thread?

在我们的程序中,我们有一个记录特定事件(字符串)的 class FooLogger 我们使用FooLogger作为unique_ptr

我们有两个线程使用这个unique_ptr实例:

  1. 线程 1 在 while 循环中记录最新事件到文件,首先检查实例是否为nullptr
  2. 当程序到达某个点(设置为nullptr )时,线程 2 释放FooLogger unique_ptr实例

但是,由于错误的交错,有可能在记录时, FooLogger的成员变量被释放,从而导致EXC_BAD_ACCESS错误。

class FooLogger {
  public:
    FooLogger() {};

    void Log(const std::string& event="") {
      const float32_t time_step_s = timer_.Elapsed() - runtime_s_; // Can get EXC_BAD_ACCESS on timer_
      runtime_s_ += time_step_s;

      std::cout << time_step_s << runtime_s_ << event << std::endl;
    }

  private:      
    Timer timer_; // Timer is a custom class
    float32_t runtime_s_ = 0.0;
};


int main() {
  auto foo_logger = std::make_unique<FooLogger>();

  std::thread foo_logger_thread([&] {
    while(true) {
      if (foo_logger)
        foo_logger->Log("some event");
      else
        break;
    }
  });

  SleepMs(50); // pseudo code
  foo_logger = nullptr;

  foo_logger_thread.join();
}

是否有可能使用某种线程同步/锁等来确保foo_logger实例在记录时不会被释放? 如果没有,有什么好的方法可以处理这种情况吗?

std::unique_ptr的目的是在std::unique_ptr超出 scope 时释放实例。 在您的情况下,您有多个线程,每个线程都可以访问该元素,并且拥有的线程可能会在其他用户之前被淘汰。

您要么需要确保所有者线程永远不会在用户线程之前被删除,要么将所有权 model 从std::unique_ptr更改为std::shared_ptr std::shared_ptr的全部目的是确保 object 只要您使用它就一直存在。

您只需要弄清楚程序需要什么并使用正确的工具来实现它。

使用与 object 消失不同的机制来确定何时停止。
(当你将一个东西用于两个不同的目的时,你经常会遇到麻烦。)

例如,一个原子bool

int main() {
  FooLogger foo_logger;
  std::atomic<bool> keep_going = true;  
  std::thread foo_logger_thread([&] {
    while(keep_going) {
        foo_logger.Log("some event");
    }
  });

  SleepMs(50);
  keep_going = false;
  foo_logger_thread.join();
}

听起来std::weak_ptr在这种情况下可以提供帮助。

您可以从std::shared_ptr制作一个并将其传递给记录器线程。

例如:

class FooLogger {
public:
    void Log(std::string const& event) {
        // log the event ...
    }
};

int main() {
    auto shared_logger = std::make_shared<FooLogger>();

    std::thread foo_logger_thread([w_logger = std::weak_ptr(shared_logger)]{
        while (true) {
            auto logger = w_logger.lock();
            if (logger)
                logger->Log("some event");
            else
                break;
        }
    });

    // some work ...

    shared_logger.reset();

    foo_logger_thread.join();
}

使用时应使用 make_shared 而不是 make_unique。 并改变:

  std::thread foo_logger_thread([&] {

  std::thread foo_logger_thread([foo_logger] {

它将创建 shared_ptr 的新实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM