[fpc-pascal] Semaphore problems

Burkhard Carstens fpc at bcsoft.de
Tue Jul 25 15:46:27 CEST 2006


Am Dienstag, 25. Juli 2006 11:59 schrieb Vinzent Hoefler:
> 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.

To prevent this very rare but indeed possible case, just use 
interlockedexchange to assign anything to self.threadid ?

Beside this, I like this implementation! This way, we have a recursive 
mutex, without depending on pthread recursive extension.

Burkhard




More information about the fpc-pascal mailing list