ThreadLocalVariable

Active context can be used to properly define thread local variable without the need of ad hoc constructs such as holder object.

With LocalVariable

Smalltalk has LocalVariable for this purpose.

ProcessLocalVariable subclass: #RegularLocalVariable
    instanceVariableNames: \''
    classVariableNames: \''
    poolDictionaries: \''
    category: 'ActiveContext-Examples'

Then with a fork

[
    self checkRegularLocal: 0.
    RegularLocalVariable value: 1.
    self checkRegularLocal: 1.
    (Delay forMilliseconds: 30) wait.
    self checkRegularLocal: 1.
    RegularLocalVariable value: 2.
    self checkRegularLocal: 2.
    p1stopped := true.
    s1 signal.
] fork.

With ActiveContext

A context can be created to define thread local semantics

Context subclass: #LocalContextTest
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'ActiveContext-Examples'
LocalContextTest>>transitionKeysFrom: keysFrom keysTo: keysTo
keysFrom keysAndValuesDo: [ :key :val | 
    keysTo at: key 
    ifAbsent: [ 
        keysTo at: key put: nil .
    ].
]. 

Then with a fork

[   
    | ctx2 |
    ctx2 := LocalContextTest ancestor: CurrentContext instance 
                 uuid: #Child1.
    ctx2 do: [
        self checkContextLocal: nil.
        value := 1.
        self checkContextLocal: 1.
        (Delay forMilliseconds: 30) wait.
        self checkContextLocal: 1.
        value := 2.
        self checkContextLocal: 2.
    ].
    p1stopped := true.
    s1 signal.
] fork.

The obvious advantage of active context is that the semantics is defined in a way that it can naturally be used for thread group local variable. The threads simply need to share the same context.