Walter is right about transitive readonly - here's the alternative

Regan Heath regan at netmail.co.nz
Thu Sep 13 03:22:44 PDT 2007


I'm still taking this is, on the surface (my first impression) is that 
it sounds like a good idea.  I do have a couple of comments...

Janice Caron wrote:
> There is no magic bullet to thread-safety. This mechanism does ensure
> that multiple threads won't try to access the same variable at the
> same time, but what it /won't/ do is prevent deadlocks. 

What sort of deadlocks, this sort...

[thread1]
scope a = readable(x);
--context switch here--
scope b = readable(y);

[thread2]
scope b = readable(y);
--or context switch here--
scope a = readable(x);

(caused by a timing issue)

or, this sort:

[thread1]
scope a = readable(x);
scope b = readable(x);  //deadlocks unless locks are re-entrant

(this one occurs in a number of forms, but the basic problem is the same)

Currently "synchronized" in D is reentrant :)

 > It's also
> still possible to screw up. For instance - you cannot get a write lock
> if you already hold a lock...
> 
>  scope a = readable(x);
>  scope b = writable(x); /* Error - b is already locked by this thread */

You mean "x is already locked.." :)

> That error is not always detectable by the compiler.

Does it 'break' the system to allow a thread with a read lock to aquire 
a write lock (assuming we block until no other thread has a read lock)?

If one of the goals of this system is to prevent aliasing style 
problems, eg.

int a;
foo(&a,&a);

void foo(int *a, int *b)
{
   if (b == 5) return ;
   *a = 5;
   //oops b == 5 now
}

?

If not then we may be able to handle this case with some clever locking 
routines.

One observation;  as these variables are scoped you know that if you 
already have a read lock then the write lock lifetime is equal to or 
less than the read lock lifetime.

And vice-versa.  So, how about the opposite case:

scope b = writable(x);
scope a = readable(x);

Allowed?  Error?  Can we also handle this case?

I suspect it might be possible to handle it but I am not sure.

> And you have to be aware that other threads may modify shared things
> when they're not locked. 

At first this comment seemed contrary to the whole purpose of your idea, 
that is until I realised you meant "you have to be aware that other 
threads may modify shared things when /you haven't got them locked 
yourself/"

So, just to clarify under your system the only time a shared object may 
change is when it's locked by the thread making the change, correct?

>  class Lookup
>  {
>      shared int[int] map_s;
> 
>      int readonly lookup(int key)
>      {
>          {
>              auto map = readable(map_s);
>              if (key in map) return map[key];
>          }
>          {
>              auto map = writable(map_s);
>              if (key in map) return map[key]; /* pay attention */
> 
>              /* read stuff from file and store it in map */
> 
>              return map[key];
>          }
>      }
>  }
> 
> See how I had to check the cache twice? Once while readable, then
> again while writable? That's because, between the unlocking of the
> read lock and the locking of the write lock, another thread could have
> got in and updated the map.

It would therefore be quite beneficial to allow overlapping/simultaneous 
read/write locks (in a single thread), if at all possible.

It seems like it may be possible to code this idea up as a library 
solution, hmmm...

Regan



More information about the Digitalmars-d mailing list