我对以下代码有两个问题:
守则:
#include <unistd.h>
#include <semaphore.h>
#include <iostream>
int main(int argc, char **argv)
{
sem_t sem;
int var = 0;
/* create, initialize semaphore */
if( sem_init(&sem,1,1) < 0)
{
perror("semaphore initilization");
exit(0);
}
int pid = fork();
static const size_t loopLen = 5;
if (0 == pid)
{ /* child process */
for (size_t i = 0; i < loopLen; ++i)
{
sem_wait(&sem);
std::string str("Child");
std::cout << str << " process: &var(" << (void*)(&var) << ") var(" << var++ << ") &sem(" << (void*)(&sem) << ")" << std::endl;
sem_post(&sem);
}
}
else
{ /* parent process */
for (size_t i = 0; i < loopLen; ++i)
{
sem_wait(&sem);
std::string str("Parent");
std::cout << str << " process: &var(" << (void*)(&var) << ") var(" << var++ << ") &sem(" << (void*)(&sem) << ")" << std::endl;
sem_post(&sem);
}
}
}
输出:
Parent process: &var(0xffffcbdc) var(0) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(0) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(1) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(1) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(2) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(2) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(3) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(3) &sem(0xffffcbe0)
Parent process: &var(0xffffcbdc) var(4) &sem(0xffffcbe0)
Child process: &var(0xffffcbdc) var(4) &sem(0xffffcbe0)
问题:
从父级和子级进程打印时,为什么var
和sem
的地址相同?我知道子进程得到父内存空间内容的副本,但我认为进程有独立且不同的地址空间,因此没有变量会在同一个内存位置 - 但这个输出似乎表明不是这样。
问题:
这段代码实际上是在同步两个进程吗?我持怀疑态度。虽然我使用sem_init
标志非零调用pshared
,但似乎子进程应该是信号量的副本。我没有看到sem
被共享的机制#34;父进程和子进程之间:信号量没有命名,我也不明白在父进程和子进程之间如何共享信号量。我怀疑每个过程只是简单地获取和发布自己的&#34; copy&#34;信号量,但我不确定。
谢谢。
答案 0 :(得分:4)
Linux使用“copy-on-write”惯用法,这意味着在您调用which python
后,父项的内存不会立即被复制(作为单独的副本)。只有子进程尝试将任何数据写入内存时才会发生复制。
理解“实际”内存地址(即物理内存中的地址)与映射地址(应用程序的内存空间中的地址)之间的区别也很重要。两个应用程序中的两个指针可能具有相同的值(虚拟地址),但这并不意味着它们确实指向相同的物理位置:Memory mapping。
答案 1 :(得分:3)
关于地址,这是因为子进程最初是父进程的精确重复。精确复制包括(虚拟)内存映射。 Read the fork
manual page了解更多信息。
关于信号量,如果你read the sem_init
manual page,你会看到
如果
pshared
非零,那么信号量在进程之间共享,并且应该位于共享内存的区域中
这个位于共享内存中的位置由您来处理,但这不是为您自动完成的。
答案 2 :(得分:1)
除了SingerOfTheFall的答案之外,我想补充说fork(2)
制作父进程的精确副本 - 相同的内存映射,相同的信号掩码,相同的文件描述符表 - 所以你实际上得到了一个真正的副本你的过程。
进程确实有不同的地址空间,但是为了理解为什么修改其中一个进程不会影响另一个进程,你应该记住虚拟和物理地址之间的区别以及所有进程(甚至是内核上的无论如何,amd64)在虚拟地址空间中执行。
长话短说 - 简而言之,CPU中有对应表(称为页表),每当您尝试访问给定地址时,CPU都会查找有问题地址的实际物理地址。内核为每个进程填充页表,并为每个进程提供相同的地址(如果未启用ASLR)。
我无法确定为什么父母和孩子之间共享信号量,但如果你的初始化是正确的,那么它就不应该从外部世界获取。
比照。