[fpc-pascal] Semaphore problems

Burkhard Carstens fpc at bcsoft.de
Tue Jul 25 11:00:25 CEST 2006


Am Montag, 24. Juli 2006 23:38 schrieb Vinzent Höfler:
> Vinzent Höfler wrote:
> > Hmm. So we'd need a mutex inside a mutex. Now I know why they call
> > it recursive. ;) So it'll be something like that:
> >
> > function Recursive_Mutex.Lock : ...;
> > begin
> >    // Lock mutex inside mutex.
> >    self.Owner_Check_Lock.Lock;
> >
> >    // Owned by current thread?
> >    if CurrentThreadId <> self.ThreadId then
> >    begin
> >       // Nope! Get the hell outta here.
> >       self.Owner_Check_Lock.Unlock;
> >       exit (NOT_OWNED);
> >    end {if};
> >
> >    // Now try locking the real mutex.
> >    if pthread_mutex_lock (self...) = 0 then
> >    begin
> >       self.Count := self.Count + 1;
> >       self.Owner_Check.Unlock;
> >       exit (SUCCESS);
> >    end {if};
> >
> >    self.Owner_Check.Unlock;
> >    exit (FAILURE);
> > end {Mutex.Lock};
> >
> > Something like that. Don't nail me on that, it's quite late and the
> > heat is still killing me. ;)
>
> I knew it. Of course this is wrong. We can only lock the mutex once,
> because we assume it's non-recursive, that was the whole point. So we
> should *first* check the count and then may lock/unlock the mutex
> accordingly.

* It's early, and I didn't dink enough coffee yet, so excuse me, if I 
overlook something ;-)

some points:

* In windows, I never used mutexes, as I didn't see the point. Usually, 
CriticalSections do what I want, except for IPC ... So I don't know if 
windows mutexes are recursive.
However, IMO a CriticalSection should be recursive, so I stick to it 
here

* pthread-Mutexes may not be used asynchronously (signal handlers are 
mentioned in the man page), so if we take that as basic rule, things 
get pretty simple: the same code is never executed simultanously from 
the same thread.

* rtleventStartWait should have a counterpart rtlEventDoneWait, which 
unlocks the internal mutex of a rtlevent.

* rtlWaitEvent should get a parameter telling it whether to call 
rtlEventDoneWait or not. (currently, it simply does it)

* protect any method of a TCriticalSection with a internal critical 
section (a simple, non-recursive form should do the job)

TCriticalSection.Enter;

  procedure internalEnter;
  begin
    OwnerThread:=GetCurrentThreadID;
    fLockCount:=1;
    ExternelLock.lock;
  end;

begin
  internal.lock;
  if OwnerThread = 0 then begin //not locked yet
    internalEnter;
  end
  else begin //allready locked
    if OwnerThread=GetCurrentThreadID then //we are the owner
      inc(fLockCount)
    else begin //other thread owns the cs
      rtlEventStartWait(fExternalLock);
      internallock.unlock;
      rtlEventWaitFor(fExternalLock,DontAutoReleaseRTLEventMutex); 
      internalLock.lock;
      rtlEventDoneWait(fExternalLock);
      internalEnter;
    end;
  end;
  internal.unlock; 
end;


TCriticalSection.Leave;

  procedure internalEnter;
  begin
    OwnerThread:=GetCurrentThreadID;
    fLockCount:=1;
    ExternelLock.lock;
  end;

begin
  internal.lock;
  try
    if OwnerThread <> GetCurrentThreadID then begin //we are not allowed
      //to leave, because we don't own it!not locked yet
      raise exception.create('leave on a foreign critical section');
    end
    else begin //we are the owner
      if fLockCount = 0 then begin
        raise exception.create('leave on a unlocked section');
      end
      else begin
        dec(fLockCount);
        if fLockCount=0 then rtlSetEvent(fExternalLock);
      end;
    end;
  finally
    internal.unlock; 
  end;
end;

* just a quick draft. This one should be pretty much the same as a 
recursive mutex, i think ..

* have to leave now, bbl. Maybe we meet in IRC later and/or setup a wiki 
page about this topic to collect and discuss proposals

Regards,
 Burkhard




More information about the fpc-pascal mailing list