类中的 C++ 后台线程 - 实例范围

标签 c++ multithreading

我有这个简单的类(class):

struct Foo {        
    void Run() {
        this->bgLoader = std::thread([this]() mutable {
            //do something 

            this->onFinish_Thread();
        });
    }
    
    std::function<void()> onFinish_Thread;
    std::thread bgLoader;
};

这是从 C-API 调用的:

void CApiRunFoo(){
    Foo foo;
    foo.onFinish_Thread = []() {
        //do something at thread end
    };
    foo.Run();
}

我想运行 CApiRunFoo,从中返回,但保持线程运行直到完成。

现在的问题是,一旦 CApiRunFoo 结束,即使后台线程仍在运行,foo 也会超出范围。如果我通过newfoo更改为object,它会运行,但会导致内存泄漏。

我正在考虑创建析构函数:

~Foo(){
    if (bgLoader.joinable()){
        bgLoader.join();
    }
}

但我不确定它是否会导致死锁,而且它可能不会导致 CApiRunFoo 返回,直到线程完成。

这个问题有什么解决方案/设计模式吗?

最佳答案

您可以返回 Foo C 程序实例:

struct Foo {        
    ~Foo() {
        if (bgLoader.joinable()) {
            run = false;
            bgLoader.join();
        }
    }
    void Run() {
        run = true;
        this->bgLoader = std::thread([this]() mutable {
            while(run) {
                // do stuff
            }

            this->onFinish_Thread();
        });
    }
    std::atomic<bool> run;
    std::function<void()> onFinish_Thread;
    std::thread bgLoader;
};

C 接口(interface):

extern "C" {

struct foo_t {
    void* instance;
};

foo_t CApiRunFoo() {
    Foo* ptr = new Foo;
    ptr->onFinish_Thread = []() {
        std::cout << "done\n";
    };
    ptr->Run();
    return foo_t{ptr};
}

void CApiDestroyFoo(foo_t x) {
    auto ptr = static_cast<Foo*>(x.instance);
    delete ptr;
}

}

还有一个 C 程序:

int main() { 
    foo_t x = CApiRunFoo();

    CApiDestroyFoo(x);
}

Demo


看来您想要 Foo当线程完成时对象自动自毁,您可以分离地运行它们并让它们 delete this;完成后。

#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <iostream>
#include <functional>
#include <mutex>
#include <thread>

// Counting detached threads and making sure they are all finished before
// exiting the destructor. Used as a `static` member of `Foo`.
struct InstanceCounter {
    ~InstanceCounter() {
        run = false;
        std::unique_lock lock(mtx);
        std::cout << "waiting for " << counter << std::endl;
        while(counter) cv.wait(lock);
        std::cout << "all done" << std::endl;
    }
    void operator++() {
        std::lock_guard lock(mtx);
        std::cout << "inc: " << ++counter << std::endl;
    }
    void operator--() {
        std::lock_guard lock(mtx);
        std::cout << "dec: " << --counter << std::endl;
        cv.notify_one();      // if the destructor is waiting
    }
    std::atomic<bool> run{true};
    std::mutex mtx;
    std::condition_variable cv;
    unsigned counter = 0;
};

struct Foo {      
    bool Run() {        
        try {
            ++ic; // increase number of threads in static counter
            bgLoader = std::thread([this]() mutable {
                while(ic.run) {
                    // do stuff
                }
                // if onFinish_Thread may throw - you may want to try-catch:
                onFinish_Thread();
                --ic; // decrease number of threads in static counter       
                delete this; // self destruct
            });
            bgLoader.detach();
            return true;  // thread started successfully
        }
        catch(const std::system_error& ex) {
            // may actually happen if the system runs out of resources
            --ic;
            std::cout << ex.what() << ": ";
            delete this;
            return false; // thread not started
        }
    }

    std::function<void()> onFinish_Thread;

private:
    ~Foo() { // private: Only allowed to self destruct
        std::cout << "deleting myself" << std::endl;
    }

    std::thread bgLoader;
    static InstanceCounter ic;
};

InstanceCounter Foo::ic{};

现在 C 接口(interface)变得更像你在问题中所拥有的。

#include <stdbool.h>

extern "C" {

bool CApiRunFoo() {
    Foo* ptr = new Foo;
    ptr->onFinish_Thread = []() {
        std::cout << "done" << std::endl;
    };
    return ptr->Run();
    // it looks like `ptr` is leaked here, but it self destructs later
}

}

Demo

关于类中的 C++ 后台线程 - 实例范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67278189/

相关文章:

c++ - Qt 5 构建错误 : extra characters after test expression

c++ - 如何计算每次读入一个字符的个数?

c++ - 整个范围内的 std::for_each 没有方便的重载吗?

c++ - 如何让 boost::iostream 以类似于 std::ios::binary 的模式运行?

sql - 在oracle 12c上用ROWNUM锁定的更新跳过

java - Android - runOnUIThread 什么时候发生?

c++ - 为什么当它作为静态成员变量出现时没有调用c++构造函数?

仅当通过文件接收(非用户)输入时才执行的 Java 程序

vb.net - 从VB中的串行读取数据时无阻塞等待

c# - 如何并行化 Kinect AllFramesReady 事件