6

考虑以下应用程序:一个 Web 搜索服务器,它在启动时基于从磁盘读取的数据创建一个大型的网页内存索引。一旦初始化,内存中的索引就不能被修改,并且会启动多个线程来服务用户查询。假设服务器被编译为本机代码并使用操作系统线程。

现在,线程模型没有提供线程之间的隔离。有缺陷的线程或任何非线程安全代码可能会损坏索引或损坏由其他线程分配并在逻辑上属于其他线程的内存。此类问题难以检测和调试。

从理论上讲,Linux 允许实施更好的隔离。一旦索引被初始化,它所占用的内存可以被标记为只读。线程可以替换为共享索引(共享内存)的进程,但除此之外具有单独的堆并且不能相互破坏。硬件和操作系统会自动检测非法操作。不需要互斥锁或其他同步原语。完全消除了与内存相关的数据竞争。

这种模式在实践中可行吗?您是否知道任何现实生活中的应用程序可以执行此类操作?或者也许有一些基本的困难使这种模型不切实际?与传统线程相比,您认为这种方法会带来性能开销吗?从理论上讲,使用的内存是相同的,但是是否存在一些与实现相关的问题会使事情变慢?

4

3 回答 3

4

显而易见的解决方案是根本不使用线程。使用单独的进程。由于每个进程都与代码和只读结构有很多共同之处,因此共享只读数据是微不足道的:根据需要对其进行格式化以在文件中使用内存并将文件映射到内存。

使用这种方案,只有变量每个进程的数据是独立的。代码将被共享,静态初始化的数据将被共享,直到被写入。如果一个进程发声,对其他进程的影响为零。完全没有并发问题。

于 2012-09-06T06:42:52.337 回答
1

您可以使用mprotect()使您的索引只读。在 64 位系统上,您可以将每个线程的本地内存映射到一个随机地址(参见这篇关于地址空间随机化的 Wikipedia 文章),这使得一个线程接触另一个线程的内存损坏几率非常小(当然,任何损坏完全错过映射内存将导致段错误)。显然,您需要为每个线程设置不同的堆。

于 2012-09-05T20:56:29.490 回答
0

我想你可能会觉得memcached很有趣。此外,您可以创建共享内存并将其以只读方式打开,然后创建线程。这不应该导致太多的性能下降。

于 2012-09-05T20:54:20.397 回答