shared_ptr没有在线程中发布自定义malloc

shared_ptr not releasing custom malloc in a thread

本文关键字:自定义 malloc 线程 ptr shared      更新时间:2023-10-16

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

我用来创建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 deleter,因为这样我就可以尝试在里面放一个断点,并检查是否调用了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;
}