[squeak-dev] Thread Safe Collections

Igor Stasenko siguctua at gmail.com
Thu Apr 24 12:39:00 UTC 2008


2008/4/24 Ralph Johnson <johnson at cs.uiuc.edu>:
> What do you mean by thread safe collections?  Should only one thread at a
> time be able to perform #do: on a collection?  Obviously we want to make
> sure that only one #add: or #remove: can be done at a time, but you should
> probably prevent #add: and #remove: when some other thread is running #do:.
> So, this will be the readers/writers problem.  You should make a
> ReaderWriterLock class with methods #read: aBlock and #write: aBlock that
> are similar to Semaphore's #critical: method.  Then you can make a subclass
> of Set called ThreadSafeSet with an instance variable rwLock that is a
> ReaderWriterLock and methods like
>
> add: anElement
> wrLock write: [^super add: anElement]
>
> do: aBlock
> wrLock read: [^super do: aBlock]
>
> It hardly seems worthwhile using traits in a case like this.  All the code
> will be very simple.  The hard part will be deciding what the granularity of
> locks should be, and how inheritance interacts with it.  Traits will not
> make this easier.  When it comes to concurrency, inheritance is the problem,
> not the solution.
>
> To answer your original question, it is a very bad idea to make every
> collection thread safe.  Making them thread safe will make them slow and
> complicated.  In general, multithreading makes things mroe complicated, and
> if you aren't careful it can make things slower, too.
>
> Keeps threads as isolated from each other as possible.  Have them interact
> though a narrow interface.  It is fine to custom-design these classes, or
> else use a few classes that are designed for communication between threads,
> such as SharedQueue or Promise.  But don't try to make most classes
> threadsafe, since that contradicts the prime imperative of keeping most
> classes simple.
>

+1 here.
If you need thread-safe collections it shows that you trying to solve
problem in a wrong way.
You can protect shared resources by locks without exposing a
collection interface.
You should look at operations with shared resources as operations
which lying on higher abstraction level, while
direct operations with collections is atomic.
Compare the number of operations which you have to wrap with locks in
higher level API with number
of operations which you will require to wrap for collections.

Whenever you need to deal with shared resource, place a lock on it,
but do it outside the collection class:

addItem: item
  self critical: [ items add: item ]

removeItem: item
  self critical: [ items remove: item ]

findItem: aString
  ^ self critical: [ items detect: [ item foo = aString] ifNone: ['NONE']].

itemsDo: aBlock
  self critical: [ items do: aBlock ]

items
  ^ self shouldNotImplement "do not expose shared resource"


> -Ralph Johnson
>


-- 
Best regards,
Igor Stasenko AKA sig.



More information about the Squeak-dev mailing list