c++ - shared_ptr 未在线程中释放自定义 malloc

标签 c++ lambda c++14

在我的代码中,我在 lambda 中创建了一个 shared_ptr,以便将 PNG 文件保存为后台任务。不幸的是,即使我有一个用于 shared_ptr 的自定义删除器,似乎字节没有正确释放。

我用来创建 shared_ptr 的代码:

std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), [](GLubyte* buffer) {
        free(buffer);
    });

为了保存文件并最终释放它:

std::thread t([=, buffer = std::move(buffer)]() mutable {
        bool done = writePNGFileFromBuffer(path, buffer.get(), width, height);
        return done;
    });
t.detach();

我尝试将 buffer.reset() 放入 lambda 中,但尽管缓冲区为空,但内存未被释放。我还尝试将创建者功能更改为类似以下内容:

std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), std::free);

但它也不起作用。现在我一直在使用 lambda 删除器,因为那时我可以尝试在其中放置一个断点并检查是否调用了 free,但内存仍然没有释放。

此外,如果我将 free(buffer.get()) 放入 lambda 中,我已经验证了该版本有效,但对我来说放置它没有任何意义,因为我正在使用 shared_ptr 为了避免这样的事情。

你能帮我释放这个缓冲区吗?非常感谢。

最佳答案

我编写了这个小测试工具来证明新/删除正在正确执行。

注意缓冲区构造函数中 new/delete[] 的使用。您对 malloc/free 的使用给代码带来了难闻的气味。求助于 free(ptr.get()) 隐藏了一些您尚未解决的其他逻辑问题。如果你把它留在程序中,它稍后会咬你。

proxy 替代了计算分配和销毁数量的 GLubyte,因此我可以使用 assert 确认每个构造都有相应的销毁。

#include <iostream>
#include <memory>
#include <thread>
#include <cassert>
#include <atomic>

using namespace std;

#define USE_PROXY 1

struct proxy
{
    proxy() {
        ++_count;
    }
    ~proxy() {
        --_count;
    }

    static std::atomic<size_t> _count;
};
std::atomic<size_t> proxy::_count = { 0 };

#if USE_PROXY
using GLubyte = proxy;
#else
//using GLubyte = uint8_t;
#endif

bool writePNGFileFromBuffer(const char* path, const GLubyte* bytes, int width, int height)
{

    return true;
}


auto main() -> int
{
    {
        int dataLength = 10000;

        auto buffer = std::shared_ptr<GLubyte>(new GLubyte[dataLength], 
                                               [](GLubyte* p) { delete[] p; });

        const char* path = "/tmp/foo";
        int width = 100, height = 100;

        std::thread t([=, buffer = std::move(buffer)]() mutable {
            bool done = writePNGFileFromBuffer(path, buffer.get(), width, height);
            return done;
        });
        t.join();
        assert(!buffer);
    }
    assert(proxy::_count == 0);
    return 0;
}

进一步思考,您可能想知道如何处理 write.... 函数中的失败情况。目前返回值被丢弃。有几种方法可以解决这个问题——一种是提供一个 lambda,可以在写操作完成时调用它。另一种是将写操作包装到 std::async 中。

bool writeSharedPNGFileFromBuffer(const char* path, shared_ptr<const GLubyte> bytes, int width, int height)
{
    return writePNGFileFromBuffer(path, bytes.get(), width, height);
}


auto main() -> int
{
    {
        int dataLength = 100;

        auto buffer = std::shared_ptr<GLubyte>(new GLubyte[10000], [](GLubyte* p) { delete[] p; });

        const char* path = "/tmp/foo";
        int width = 100, height = 100;

        auto f = std::async(launch::async, writeSharedPNGFileFromBuffer, path, move(buffer), width, height);
        // f is a std::future - a handle to somewhere the result will eventually land.
        // perform main thread work here...
        // ... and get the return value when we're ready to deal with it
        auto written = f.get();
        cout << "written: " << written << endl;
        assert(!buffer);
    }
    assert(proxy::_count == 0);
    return 0;
}

关于c++ - shared_ptr 未在线程中释放自定义 malloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31200796/

相关文章:

c++ - 如何防止默认初始化具有类类型的 const 变量

c++ - 为什么升级到Centos 5.5后MAP_GROWSDOWN会出现SIGBUS错误?

c++ - 如何检查分离的 std::thread 是否仍在运行?

c++ - 乘以可变数量的参数

c++ - 英特尔 icpc 和 C++14:如何 constexpr std::complex?

c++ - 生命模拟的有效方法

java - 如何定义以可序列化的 lambda 作为参数的函数

c# - 创建 Lambda Contains 表达式

java - 使用 Java 流从列表中的列表中平均特定值

C++析构函数过早调用