有没有办法确定 free() 是否会失败?

发布于 2024-08-10 04:12:31 字数 363 浏览 3 评论 0原文

有没有办法确定如果在某个内存块指针上调用 free() 是否会失败?

我遇到以下情况:访问共享资源的线程失败可能处于释放所述资源的状态。现在我需要设计一种安全的方法来清理这个共享资源。

当然,我已经为正常情况分配了资源的所有权,但是上述极限情况又如何呢?

更新:如果我使用额外的同步机制,它只会需要做更多的清理工作,并且可能涉及额外的限制条件。如果可能的话,我想限制/避免这些。

解决方案:我最终决定进行重构。感谢所有贡献者。你们摇滚!

Is there a way to determine if free() would fail if ever called on a certain memory block pointer?

I have the following situation: a thread having access to a shared resource fails whilst it may have been in the state of freeing the said resource. Now I need to devise a safe way to clean-up this shared resource.

Of course I have assigned ownership of the resource for the normal case but what about the aforementioned limit case?

UPDATED: If I use additional synchronizing mechanisms it only makes more cleaning up to do and might involved additional limit conditions. I'd like to limit/avoid those if possible.

Resolution: I finally settled on performing re-factoring. Thanks to all contributors. You guys rock!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

白日梦 2024-08-17 04:12:31

我见过各种各样的尝试,包括这个:

void m_free(void **p)
{
        if (*p != NULL) {
                free(*p);
                *p = NULL;
        }
}

取消引用类型双关指针不仅会破坏各种平台,而且只有在初始化、释放和重新初始化每个现有的每个指针时,“插入此示例”才能起作用。函数(包括编译的库)并使用具有相同功能的 C 库。

然后,处理优化和无锁线程安全问题。呸!

简而言之,如果您无法跟踪在单个函数中分配的内容,那么是时候重构该函数了。做得足够多......你会发现对更安全的 free() 的需求很快就消失了。如果 Valgrind 在它支持的平台上工作,那么它就是您的朋友。根据你的标签,它确实是你的朋友:)

或者,使用 malloc()进行垃圾收集需要您自费,具体取决于您如何分配事物并完全摆脱 free() 。之后,调试几乎变得非常有趣。

希望您要进行重构吗?虽然您似乎也遇到了互斥问题,但它只会导致重构。即,让 free() 之前的行阻塞,或者在尝试获取锁时失败......并在具有锁的线程中将释放的指针设置为 NULL,至少在您实现的结构中。

I've seen all kinds of attempts, including this one:

void m_free(void **p)
{
        if (*p != NULL) {
                free(*p);
                *p = NULL;
        }
}

Not only does dereferencing a type punned pointer break various platforms, 'plugging this example in' can only work if you initialize, free and re-initialize every single pointer in every single existing function (compiled libs included) and work with a C library that does the same.

Then, deal with optimization AND lock free thread safe issues. BAH!

In short, if you can't keep track of what you have allocated in a single function, its time to re factor that function. Do that enough .. and you'll find that the need for a safer free() quickly goes away. Valgrind is your friend if working on a platform that it supports. According to your tags, it really is your friend :)

Or, use a malloc() that sports garbage collection at your own expense, depending on how you allocate things and get rid of free() altogether. After that, debugging becomes almost terminally interesting.

Hopefully, you are off to re-factor? While you appear to be having an issue (also) with mutual exclusion, it just leads back to re-factoring. I.e, let the line before free() block, or fail when trying to get a lock .. and set freed pointers to NULL in the thread that has the lock, at least in structures that you implement.

傲娇萝莉攻 2024-08-17 04:12:31

我不相信有一个符合您要求的界面。

不过,我可以想到一些技巧。您可以让容易失败的线程调用 free() 的包装器,而不是直接调用 free() ;包装器可以保存地址或最后几个地址,以便您可以确定该块是否被释放。您还可以阻止信号、建立临界区或处理任何可能中断*线程的事情。

更新:垂死的线程在退出/清理之前是否释放过该内存?我经常为不需要在稳定状态下释放的内存编写 malloc 前端(作为速度优化)。如果线程只是自行设置,则可以在线程启动之前分配内存,并让线程调用前端,该前端仅分发动态块中未链接的、不可释放的部分。它会运行得更快,然后当线程终止时,您可以立即释放整个块。这里的总体想法是让容易失败的线程通过调用可以事后清理的服务来获取其内存。

还有一个想法:每线程堆怎么样?如果可以说服线程从自己的堆中分配仅在其生命周期内所需的内存,那么可以很好地组织清理任务,以便在线程重新加入父级时释放整个线程堆。

I don't believe there is a conforming interface that does what you want.

I can think of a few tricks, however. You could have the failure-prone thread call a wrapper around free() instead of free() directly; the wrapper could save the address or the last few addresses so that you can determine if the block was released. You could also block signals, establish a critical section, or deal with whatever else might interrupt the *thread.

Update: Does the dying thread ever free this memory prior to exit/cleanup? I've frequently written malloc front-ends (as a speed optimization) for memory that doesn't need to be freed in a steady-state. If the thread is just setting itself up, you could malloc the memory prior to thread launch and have the thread call a front-end that just hands out unlinked, unfreeable pieces of the dynamic block. It will run faster and then when the thread dies you can just free the whole block all at once. The general idea here is to have the failure-prone thread get its memory by calling a service that can clean up after-the-fact.

Yet another idea: what about a per-thread heap? If threads could be persuaded to allocate memory needed only during their lifetime from their own heap, that would nicely organize the cleanup task into freeing the entire thread heap when the thread rejoins a parent.

心头的小情儿 2024-08-17 04:12:31

我认为没有办法完全按照你的要求去做。

问题在于,无法确定正在死亡的线程死亡时处于什么状态。它是否只是简单地调用了 free() 就不再继续了? free() 是否将该块添加回空闲列表?你说不出来。


如果线程以这种方式终止的情况非常罕见(因此可以保留未释放的内存 - 您只是想知道不要使用它),那么以下(使用 Windows 调用)会释放内存并“标记” ' 它对其他线程来说是免费的:

void* ptr;
...
void* desiredPtr = ptr;
if(InterlockedCompareExchangePointer(&ptr, NULL, desiredPtr) == desiredPtr)
  free(desiredPtr);

它的作用是确保只有一个线程正在尝试释放内存,并且在释放内存之前将地址设置为 NULL,这样其他线程就不会尝试 free() 它。


如果偶尔保留内存是不可接受的,那么最好的方法可能是使用一个单独的线程,其唯一的工作就是释放内存。然后,其他线程可以将空闲内存线程的空闲请求排队。由于释放内存线程非常简单,因此它永远不会死亡并且可以正确完成释放操作。

I think there is no way to do exactly what you're asking.

The problem is that there is no way to determine what state the dying thread was in when it died. Did it simply call the free() and get no further? Did free() add the block back to the free list? You can't tell.


If it's a really rare condition for the thread to die in this way (and so it's okay to leave the unfreed memory around - you just want to know not to use it) then the following (using Windows calls) frees the memory and 'marks' it as free to your other threads:

void* ptr;
...
void* desiredPtr = ptr;
if(InterlockedCompareExchangePointer(&ptr, NULL, desiredPtr) == desiredPtr)
  free(desiredPtr);

What this does is it makes sure that ONLY one thread is trying to free the memory and before it does it sets the address to NULL so no other thread will try to free() it.


If it's unacceptable for the memory to be occationally kept around then the best way might be to have a separate thread whose only job is to free memory. The other threads can then queue up free requests for the free-memory-thread. Since the free-memory-thread is so simple it should never die and can finish the free operation properly.

北方。的韩爷 2024-08-17 04:12:31

如果您使用有效指针调用free,我不知道它会如何失败。如果失败,则一定是由于指针无效。

除了同步对共享内存的访问(例如使用互斥体)之外,所有权还必须是也清除以避免诸如双重释放之类的情况。双重释放是指两个或多个线程拥有有效指针,但随后多个线程尝试释放内存。尽管第二个线程具有非空指针,但它不再有效。

如果您在 C/C++ 中遇到内存问题,您可以尝试使用内存库,例如 HeapAgent 。像这样的内存库将检测并初始化每个内存分配。在释放内存之前,它首先检查内存指针是否有效以及是否存在缓冲区溢出错误。不应该有任何代码更改,因为它可以简单地替换内置的 malloc/free。此外,该库还可以帮助查找内存泄漏、覆盖和无效引用。

解决问题的另一种策略可能是将资源清理集中到一个线程。当线程使用完资源后,它只是将其标记为可供垃圾收集器线程清理。

当然,还有C计划——使用Java……开玩笑。

If you are calling free with a valid pointer, I don't see how it would fail. If it is failing, it must be due to an invalid pointer.

In addition to synchronizing access to shared memory (with a mutex, for example), ownership must be clear too to avoid cases like double-freeing. Double-freeing is when two or more threads have a valid pointer, but then more than one thread attempts to free the memory. Despite the second thread having a non-null pointer, it is no longer valid.

If you are plagued with memory issues in C/C++, you might try a memory library like HeapAgent. A memory library like this will instrument and initialize each memory allocation. Before freeing memory, it checks if the memory pointer is valid first and there were no buffer overrun errors. There should be no code changes as it can simply replace the built-in malloc/free. In addition, the library can help find memory leaks, overwrites, and invalid references.

Another strategy to address your problem may be to centralize the resource cleanup to one thread. When a thread is done with the resource, it just marks it available to be cleaned up by the garbage collector thread.

Of course, then there is Plan C -- use Java... Just kidding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文