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技术内幕》在全国各大书店及网城均有销售:
阅读(6662) | 评论(0) | 转发(0) |