6

mprotect() is used to protect memory pages, for example, making pages read-only. It sets this protection for the whole process, that is, if a page is read-only, no thread can write to that page. Is there a way to protect pages in different ways for different threads? For example, 1 thread can write to page P, and all other threads in my program can only read from P.

4

2 回答 2

1

如果您在“克隆”系统调用中使用 CLONE_VM 标志创建线程(这就是您通常所说的线程),那么 MMU 设置与父线程的设置相同。

这意味着两个线程都可以进行写访问。

如果你不使用 CLONE_VM 标志,那么两个线程根本就没有共享内存!

(pthread_create() 在内部设置 CLONE_VM 标志)。

可以做你想做的事 - 但是这将非常困难:

使用共享内存函数(例如 shmget())而不是标准函数(例如 malloc())分配所有内存块。

如果创建了一个新线程,则直接使用“clone()”而不是“pthread_create()”,但未设置 CLONE_VM 标志。

共享内存在线程之间共享,而由“正常”内存分配函数(例如 malloc())创建的线程不在线程之间共享。mmap() 映射内存也是如此。

当创建新线程时,会复制此类内存块(由 malloc 或 mmap 创建),以便两个线程在同一地址拥有自己的内存块副本。如果一个线程写入此地址,则另一个线程将看不到更改。

分配更多的“共享”内存相当棘手。如果只应该在分配线程和尚未创建的子线程之间共享内存,这很容易。在已经运行的线程之间或在作为不同已运行线程的(间接)子线程的线程之间共享内存是很困难的。

线程没有共享堆栈内存,因此它们无法访问彼此的堆栈。

默认情况下不共享全局变量和“静态”变量——要使它们在线程之间“共享”,需要进行一些棘手的编程。

于 2013-08-23T19:47:05.950 回答
1

使用较新的 Intel CPU,您可以将内存保护密钥 [1] 用于进程中每个线程的不同访问设置。在 Linux 上,运行lscpu并检查pkuospke标志。

手册页 [2] 上的示例有点过时,因为不再需要手动调用相应的系统调用。相反,glibc 提供了以下 API 调用:

  • pkey_alloc() 分配一个新的密钥(16 个可用)
  • pkey_set() 设置给定密钥的权限
  • pkey_mprotect() 将密钥应用于给定的内存区域
  • pkey_free() 释放密钥

由于维护每个保护密钥的权限位的寄存器是线程本地的,因此每个线程可以有不同的保护设置。保护键设置只能进一步锁定通用设置,不影响指令获取。

[1] https://www.kernel.org/doc/Documentation/x86/protection-keys.txt

[2] http://man7.org/linux/man-pages/man7/pkeys.7.html

于 2019-07-08T17:09:33.787 回答