[fpc-pascal] Semaphore problems

Vinzent Hoefler JeLlyFish.software at gmx.net
Tue Jul 25 11:59:52 CEST 2006


On Tuesday 25 July 2006 09:04, Burkhard Carstens wrote:
> Am Dienstag, 25. Juli 2006 10:46 schrieb Micha Nelissen:
>
> > function Recursive_Mutex.Lock:...;
> > begin
> >    // Owned by current thread?
> >    if CurrentThreadId <> self.ThreadId then
> >    begin
> >       result := pthread_mutex_lock (self...);
> >       if result <> 0 then exit;
> >       self.ThreadId := CurrentThreadId;
> >       self.Count := 1;
> >    end else begin
> >       Inc(self.Count);
> >    end;
> >    result := SUCCESS;
> > end {Mutex.Lock};
> >
> > function Recursive_Mutex.Unlock: ...;
> > begin
> >   if CurrentThreadId <> self.ThreadId then
> >     exit(ENOTOWN);
> >   assert(self.Count > 0);
> >   dec(self.Count);
> >   if self.Count = 0 then
> >   begin
> >     self.ThreadId := 0; // a threadid that does not occur in system
> >     pthread_mutex_unlock(self...);
> >   end;
> >   result := SUCCESS;
> > end;
> >
> > I don't see the need for Owner_Check_Lock anymore ? :-)
>
> You have to prevent that 2 concurrent threads call lock
> simultanously,

No. That's not a problem. See the explanation below.

Perhaps the line "if result <> 0 then exit;" may be kind of superfluous, 
or even dangerous, because it would return from the lock operation 
without actually locking it, but well - if it goes wrong here, we're 
screwed anyway. At least the caller could check, if it did.

> so you have to take an internal lock before touching
> internal vars like self.ThreadID ?

First I thought that, too. But after looking at and thinking about it a 
while, the race you mention could only occur if the *same* thread would 
call Lock() simultaneously, and that can't happen.

In the case two different threads enter here, they may both still see 
"0" and are trying to continue then, but only one of them will acquire 
the mutex sucessfully, leaving the other suspended. Once the suspended 
thread continues, it actually owns the mutex, so everything's ok then.

Ok, there's a glitch: The read and write of self.ThreadId is required to 
be atomic, so that a thread entering may either see "0" or the owner's 
thread id when checking, otherwise it could be possible, it sees its 
own thread_id due to a partial update and *then* it goes really wrong.


Vinzent.




More information about the fpc-pascal mailing list