Pharo 10.0多进程Singleton模式实现:如何通过测试?
Pharo 10.0(Smalltalk)多进程单例模式实现问题
我在Pharo 10.0(Smalltalk)中实现多进程环境下的Singleton(单例)模式,但无法通过以下测试用例。先后尝试两种实现方式均失败,寻求解决方案。
测试代码
"SingletonTest" testCurrent | semaphore object1 object2 | Singleton initialize. semaphore := Semaphore new. [ Processor yield. object1 := Singleton current. semaphore signal ] fork. object2 := Singleton current. semaphore wait. self assert: object1 identicalTo: object2
第一种失败实现
"Singleton class" current Transcript show: 'start'; cr. current := current ifNil: [ Transcript show: 'creating..'; cr. self new ]. ^ current initialize isProcessing := false. current := nil
第二种失败实现
"Singleton class" current [ isProcessing ] whileTrue: [ ]. isProcessing := true. current := current ifNil: [ (Delay forSeconds: 2) wait. self new ]. isProcessing := false. ^ current initialize isProcessing := false. current := nil
问题分析与解决方案
失败原因
- 第一种实现:
current := current ifNil: [...]并非原子操作。多进程竞争时,第一个进程还在执行self new创建实例的过程中,第二个进程检查current仍为nil,会进入分支创建新实例,导致最终生成多个不同的单例对象。 - 第二种实现:忙等待
[isProcessing] whileTrue: []与后续设置isProcessing := true的操作不是原子的。两个进程可能同时检测到isProcessing为false,进而都进入创建分支,同样会生成多个实例。
正确实现
利用Smalltalk的Semaphore实现互斥临界区,保证current的检查与创建操作是原子执行的:
"Singleton class" current | instance | semaphore ifNil: [ semaphore := Semaphore forMutualExclusion ]. semaphore critical: [ instance := current ifNil: [ self new ]. current := instance ]. ^ instance initialize semaphore := nil. current := nil
说明
Semaphore forMutualExclusion创建一个互斥信号量,确保同一时间只有一个进程能进入critical:代码块。- 临界区内的代码原子执行,避免了多进程同时检查
current是否为nil的竞争问题,保证只会创建唯一的单例实例。
内容的提问来源于stack exchange,提问作者Yuji Hamaguchi
相关产品推荐
相关产品推荐

