何时不使用 RAII 进行资源管理

发布于 2024-09-10 14:39:02 字数 74 浏览 2 评论 0原文

谁能给我提供一个或多个具体示例,说明 RAII 不是最有效的资源管理方法,为什么?

Can anyone provide me with one or more concrete examples in which RAII was not the most efficient method for resource management, and why?

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

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

发布评论

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

评论(5

相权↑美人 2024-09-17 14:39:02

我能想到的唯一 RAII 不是解决方案的情况是多线程关键区域锁定管理。一般来说,建议获取关键区域锁(考虑资源)并将其保存在 RAII 对象中:

void push( Element e ) {
   lock l(queue_mutex);  // acquire on constructing, release on destructing
   queue.push(e);
}

但在某些情况下,您不能将 RAII 用于此目的。特别是,如果循环条件中使用的变量由多个线程共享,并且您无法在整个循环执行中持有锁,则必须使用不同的机制获取和释放锁:

void stop_thread() {
   lock l(control_mutex);
   exit = true;
}
void run() {
   control_mutex.acquire();
   while ( !exit ) { // exit is a boolean modified somewhere else
      control_mutex.release();
      // do work
      control_mutex.acquire();
   }
   control_mutex.release();
}

甚至可以使用 RAII通过 (ab)using operator, 现在我想到了,但我从未真正想到过。但我想这并不是很自然:

void run() {
   while ( lock(control_mutex), !exit ) {
      // do work
   }
}

所以我想答案不是我能想象的...

编辑:使用 RAII 针对同一问题的其他解决方案:

@马克·兰塞姆

bool should_exit() const {
   lock l(mutex);
   return exit;
}
void run() {
   while ( !should_exit() ) {
      // do work
   }
}

@fnieto

void run() {
   while (true) {
      {  lock l(mutex);
         if (exit) break;
      }
      // do work
   }
}

The only case I can think of where RAII was not the solution is with multithreaded critical region lock management. In general it is advisable to acquire the critical region lock (consider that the resource) and hold it in a RAII object:

void push( Element e ) {
   lock l(queue_mutex);  // acquire on constructing, release on destructing
   queue.push(e);
}

But there are situations where you cannot use RAII for that purpose. In particular, if a variable used in a loop condition is shared by multiple threads, and you cannot hold the lock for the whole loop execution, then you must acquire and release the lock with a different mechanism:

void stop_thread() {
   lock l(control_mutex);
   exit = true;
}
void run() {
   control_mutex.acquire();
   while ( !exit ) { // exit is a boolean modified somewhere else
      control_mutex.release();
      // do work
      control_mutex.acquire();
   }
   control_mutex.release();
}

It might even be possible to use RAII by (ab)using operator, now that I think of, but I had never actually thought of it. But I guess this is not really natural:

void run() {
   while ( lock(control_mutex), !exit ) {
      // do work
   }
}

So I guess that the answer is that not that I can imagine...

EDIT: Other solutions for the same problem using RAII:

@Mark Ransom:

bool should_exit() const {
   lock l(mutex);
   return exit;
}
void run() {
   while ( !should_exit() ) {
      // do work
   }
}

@fnieto:

void run() {
   while (true) {
      {  lock l(mutex);
         if (exit) break;
      }
      // do work
   }
}
勿忘心安 2024-09-17 14:39:02

有时需要两阶段初始化(创建,然后初始化,然后使用)。

甚至是三阶段:在我们的产品中,有一组独立的对象,每个对象运行一个线程,并且能够通过优先级继承队列订阅任意数量的其他对象(包括其本身)。对象及其订阅在启动时从配置文件中读取。在构造时,每个对象 RAII 拥有其所能提供的一切(文件、套接字等),但没有对象可以订阅其他对象,因为它们是以未知的顺序构造的。因此,在构造所有对象之后,将在第二阶段建立所有连接,在第三阶段建立所有连接后,线程将被释放并开始消息传递。同样,关闭也是多阶段的。

Sometimes two-stage initialization (create, then init, then use) is needed.

Or even three-stage: in our product, there is a collection of independent objects, each running a thread and able to subscribe to any number of other objects (including itself) via priority-inheriting queues. Objects and their subscriptions are read from the config file at startup. At construction time, each object RAIIs everything it can (files, sockets, etc), but no object can subscribe to others because they are constructed in unknown order. So then after all objects are constructed there's the second stage where all connections are made, and third stage when, once all connections are made, the threads are let go and begin messaging. Likewise, shutdown is mutli-stage as well.

演多会厌 2024-09-17 14:39:02

GC 可以为程序员处理循环数据结构的内存,而 RAII 则需要程序员在某处手动中断循环。

GC can handle the memory of cyclic data structures for the programmer while RAII will require the programmer to manually break the cycle somewhere.

秋日私语 2024-09-17 14:39:02

RAII 意味着资源的所有权是通过语言构造(尤其是但不限于构造函数和析构函数)提供的保证来定义和管理的。

C++ 中 RAII 的要点是资源所有权策略实际上可以由语言强制执行。 RAII 的一个较小的替代方案是 API 建议调用者(例如,通过注释或其他文档)显式执行 ACQUIRE()RELEASE()< /code> 在特定时间进行操作。这种政策不能由语言强制执行。

因此,最初的问题是另一种方式来询问是否存在不可执行的资源管理方法比 RAII 更可取的情况。 我能想到的唯一情况是您故意规避语言中现有的资源管理结构,并编写自己的框架。例如,您正在实现一个垃圾收集脚本语言解释器。原子的“虚拟分配”可能会与内存块玩游戏。类似地,基于池的分配器期望程序最终调用 DESTROY_POOL() 操作,并产生全局后果(即,从该池分配的任何项目都将失效)。

RAII means that the ownership of resources is defined and managed through the guarantees provided by the language constructs, most notably, but not limited to, constructors and destructors.

The point of RAII in C++ is that the resource ownership policy can actually be enforced by the language. A lesser alternative to RAII is for the API to advise the caller (e.g., through comments or other documentation) to explicitly perform ACQUIRE() and RELEASE() operations at certain times. That kind of policy is not enforceable by the language.

So the original question is another way to ask whether there are cases when an unenforceable approach to resource management is preferable to RAII. The only cases I can think of are where you are deliberately circumventing the existing resource management constructs in the language, and writing your own framework. For example, you are implementing a garbage collected scripting language interpreter. The "virtual allocation" of atoms will likely play games with memory blocks. Similarly, a pool based allocator expects the program to eventually call a DESTROY_POOL() operation, with global consequences (i.e., any item allocated from that pool will be invalidated).

心作怪 2024-09-17 14:39:02

在资源释放可能失败的情况下,RAII 可能不足以管理该资源(因为析构函数不应抛出)。不过,RAII 可能仍然是该解决方案的一部分。

In cases where resource release may fail, RAII may not be sufficient to manage that resource (since destructors shouldn't throw). RAII may still be part of that solution though.

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