《UNIX技术内幕》勘误及问题解答_25



From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: RE: 关于《UNIX技术内幕》的勘误及遇到的问题_25
Date: Fri, 17 Feb 2012 11:08:10 +0800

郝先生,

对于问题4中你的回复,我还是有些疑问,具体如下:

----------------------------------

问题4:是这样吗?是否我理解错了?
[郝]:事实上u_osema定义为 Semaphore *u_osema[4],其每个元素都是Semaphore *,且从内核全局semaphs中获得,所以尽管子进程拷贝了父进程的u_osema数据,但是它们都指向同一个
Semaphore指针(如果不为NULL),这样Acquire或者Release还是操作的同一个元素。所以可以实现同步。

-----------------------------------


你 提到“u_osema定义为 Semaphore *u_osema[4],其每个元素都是Semaphore *”,这个我同意。但问题是“Semaphore *”这个指针指向的是一个虚拟地址,而不是物理地址。这也就决定了以后父、子进程所指向的不是同一个元素。代入619页例1,如下:

首先,设定一个Semaphore * res,以记录对应的u_osema[sd]。且假设res本身的地址为0x1000(虚拟地址)

1)在创建子进程之前,第4行:“sd = CreateSemaphore(1);”。父进程已创建了信号量sd。假设 res = u_osema[sd],且假设的 res 所指向的地址为 0x2000。之后,执行fork。

2)假设父进程先执行,则在整个执行过程中,res本身的地址都是0x1000,它所指向的地址都是0x2000,且都在父进程空间里

3) 到了子进程执行时,res本身的地址也是0x1000,它所指向的地址也是0x2000,这些值都是从父进程里复制过来的。但是,这里是子进程空间。虽然 虚拟地址是一样的,但父、子进程所对应的实际物理地址空间是不同的,也就是各自的数据是独立的。因此,父进程里修改了u_osema[父进程的 sd]->s的值,这并不等于子进程里u_osema[子进程的sd]->s这个值被改变。换句话说,u_osema[父进程的sd]和 u_osema[子进程的sd]有相同的虚拟地址(不是物理地址),且指向的目标虚拟地址都是相同的,但由于处于不同的物理空间,因此它们最终指向的数据 是不一致的。

最后,如果要使u_osema[父进程的sd]和u_osema[子进程的sd]都指向相同的变量,则需要对应分配相同的“物理地址”;或者通过内存映射等方式实现指向一致。

以上是我的理解,不知道对不对?

[郝]: 看得出来你对虚拟内存理解的不错,但是有一点要注意:semaphs和u_osema都是在内核空间的,而内核空间只有一份,并一直驻留在内存中,所以 semaphs的地址不会改变(不管是虚拟还是物理)。这样u_osema[sd]中存储的正式semaphs中的元素,也就是&semaphs[0],&semaphs[1],...,所以只要子进程复制了u_osema[sd]的值,它就会指向同一个地方。





From: qf.hao@hotmail.com
To: quntmec@hotmail.com
Subject: RE: 关于《UNIX技术内幕》的勘误及遇到的问题_25
Date: Fri, 17 Feb 2012 09:13:22 +0800




From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: 关于《UNIX技术内幕》的勘误及遇到的问题_25
Date: Thu, 9 Feb 2012 17:37:16 +0800

郝先生,

613页,有关信号量,我的理解如下:

1、全局结构与数组

(1)struct Semaphore,它是“信号量“的结构体,它的成员解释如下:
s代表信号量;ref代表该信号量总共被多少个进程共享;flag代表该信号量当前的状态

(2)struct Semaphs,它是所有信号量的集合信息,它的成员解释如下:
semas[64]代表系统最多可以同时提供64个信号量;flag代表整个信号量集合的状态,如果是S_WANT,表示64个信号量已分配完,没有空余。

(3)u_osema[4],代表1个进程最多可以同时使用4个信号量,其中每个元素代表1个信号量

(4)u_rsema[4]:问题2

2、函数

(1)AcquireSemaphore(),该函数的主要作用是执行“P操作“。

(2)ReleaseSemphore(),该函数的主要作用是执行“V操作”。



问题1:以上的理解对吗?
[郝]:对,很好!
问题2:u_rsema[4]有什么具体的作用吗?是指获得该信号量(对应u_osema[i])的进程的个数吗(即如果信号量初值不为1的情况,表明可以有多个进程同时获得该信号量)?
[郝]:记录本进程已经获得的信号量, u_rsema[0]记录u_osema[0]的是否获得(>0获得,否则没获得)。
问题3:按照struct Semaphore的定义,所有的信号量都是无名的。再有,整个系统只能同时存在64个信号量,且每个进程最多只能使用其中4个信号量,是这样吗?如果是的话,为何这样设计?
[郝]:是这样的,简单起见,且性能比较好。


3、 619页,应用示例的例1中,第4行:“sd = CreateSemaphore(1);”,可见,在创建子进程之前,父进程已创建了信号量sd,且它的初值为1, 即,u_osema[sd]->s的值为1。在fork之后,父、子进程都各自拥有自己的sd,且初值都是1。

假如父进程先运行, 则执行AcquireSemaphore(sd),即执行“P操作”,这时,u_osema[父进程的sd]->s的值变为0。接着,父进程执行 write操作。假设在write执行完成前,父进程的时间片用完了,系统切换至子进程执行。子进程会首先执行 AcquireSemaphore(sd),即“P操作”。由于父、子进程各自拥有独立的数据空间,因此这时u_osema[子进程的sd]->s 的值仍然为1。可见,”P操作“是会成功的!这显然是不对的!按照程序的本意,父进程的“P操作”应该会阻止子进程对该信号量的获取(即阻止子进程进入临 界区)。

问题4:是这样吗?是否我理解错了?
[郝]:事实上u_osema定义为 Semaphore *u_osema[4],其每个元素都是Semaphore *,且从内核全局semaphs中获得,所以尽管子进程拷贝了父进程的u_osema数据,但是它们都指向同一个
Semaphore指针(如果不为NULL),这样Acquire或者Release还是操作的同一个元素。所以可以实现同步。



此外,勘误,无
[郝]:下一版会考虑多增加说明(包括如上内容)。


Steve



《返璞归真--UNIX技术内幕》在全国各大书店及网城均有销售:
京东
亚马逊                          China pub
上学吧                          1号店

上一篇:《UNIX技术内幕》--第3章 虚拟内存


下一篇:《返璞归真--UNIX技术内幕》--源代码