如何让std :: thread在执行对象的成员函数后自动删除该对象

时间:2019-04-24 03:02:43

标签: c++ memory-management stdthread

我想实现一个<script src="https://d3js.org/d3.v5.min.js"></script>类,该类在另一个线程中完成某些工作,并且我不想让用户手动删除该对象。我的cmmand类如下:< / p>

command

我这样使用它:

class Cmd {
 public:
  void excute() {
    std::cout << "thread begins" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));  // do some work
    std::cout << "thread ends" << std::endl;
  }

  void run() {
    // I want std::unique_ptr to delete 'this' after work is done,but does't work
    std::thread td(&Cmd::excute, std::unique_ptr<Cmd>(this));
    td.detach();
  }

  // test if this object is still alive
  void ok() { std::cout << "OK" << std::endl; }
};

就像在评论中一样,该对象在cmd线程完成后仍然存在,我想知道如何实现这种功能。

编辑

int main() { Cmd *p = new Cmd(); p->run(); // waiting for cmd thread ends std::this_thread::sleep_for(std::chrono::seconds(3)); p->ok(); // I thought p was deleted but not return 0; } 的用户不知道cmd何时完成,因此,不断发展的用例将导致UB。

cmd

已关闭

我在测试方面犯了一个错误,实际上该对象在线程结束后被删除了。使用附加的成员变量std::unique_ptr<Cmd> up(new Cmd); // or just Cmd c; up->run(); // cmd will be deleted after out of scope but cmd::excute may still need it 进行以下测试会更加清楚。

int i

流淌的输出证明对象已删除。

#include <functional>
#include <iostream>
#include <stack>
#include <thread>

using namespace std;

class Cmd {
 public:
  ~Cmd() { std::cout << "destructor" << std::endl; }

  void excute() {
    std::cout << i << " thread begins" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));  // do some work
    std::cout << i << " thread ends" << std::endl;
  }

  void run() {
    // I want std::unique_ptr to delete 'this' after work is done,but it seems
    // not working
    std::thread td(&Cmd::excute, std::unique_ptr<Cmd>(this));
    td.detach();
  }

  // test if this object is still alive
  void ok() { std::cout << i << " OK" << std::endl; }

  int i;
};

int main() {
  Cmd *p = new Cmd();
  p->i = 10;
  p->run();

  // waiting for cmd thread ends
  std::this_thread::sleep_for(std::chrono::seconds(3));

  p->ok();  // I thought p was deleted but not

  return 0;
}

但是正如某些同仁所建议的那样,这不是一个好的设计,请尽量避免。

2 个答案:

答案 0 :(得分:1)

您可以使用std::future而不是线程来指示状态。然后,您可以等待任务完成,也可以完全忽略将来。

#include <future>
#include <chrono>
#include <mutex>
#include <iostream>

class Cmd {
public:
    std::future<void> run() {
        std::lock_guard<std::mutex> lock(startMutex);
        if (started) {
            throw std::logic_error("already started");
        }
        started = true;

        // Take copies here, so that it doesn't matter if Cmd is destroyed
        int i_ = i;
        return std::async(std::launch::async, [i_]() {
            std::this_thread::sleep_for(std::chrono::seconds(2));
            std::cout << i_ << std::endl;
        });
    }

    int i = 0;

private:
    std::mutex startMutex;
    bool started = false;
};

int main() {
    auto p = std::make_unique<Cmd>();
    p->i = 10;
    auto f = p->run();
    p.reset();

    // Do some other work

    // Wait for the task to finish (or use f.get() if there is no need to
    // do some other work while waiting)
    if (f.valid()) {
        std::future_status operation;
        do {
            // Do some other work

            operation = f.wait_for(std::chrono::milliseconds(1));
        } while (operation != std::future_status::ready);
    }
}

答案 1 :(得分:0)

有两种方法可以自动删除动态创建的内存。

  1. 在客户端代码(主要功能)中,应使用unique_pointer之类的智能指针,以便一旦对象超出范围,它将自动在unique_poiter析构函数中释放

  2. 您可以创建自己的smart pointer,它将成为Cmd类的包装器。并且不得不重载一些运算符。该智能指针还将处理析构函数中动态分配的内存。客户端代码在动态创建Cmd对象时应使用此智能指针。