Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 19 Jul 2001 09:46:27 -0400
From:      "Louis-Philippe Gagnon" <louisphilippe@macadamian.com>
To:        <tlambert2@mindspring.com>
Cc:        <freebsd-hackers@FreeBSD.ORG>
Subject:   Re: flock/pthread bug?
Message-ID:  <203501c11059$35755420$2964a8c0@macadamian.com>
References:  <Pine.BSF.4.21.0107181320030.94740-100000@InterJet.elischer.org> <1fbd01c10fba$499834d0$2964a8c0@macadamian.com> <3B5690A1.8EDD0812@mindspring.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Lots of ideas to try (esp. since I don't need FIFO); thanks!

LPG

----- Original Message ----- 
From: "Terry Lambert" <tlambert2@mindspring.com>
> Louis-Philippe Gagnon wrote:
> > 
> > From: "Julian Elischer" <julian@elischer.org>
> > > probably you should try :
> > >
> > >      #define   LOCK_NB        0x04      /* don't block when locking */
> > >
> > But I do want to block; I just don't want the whole process to block.
> 
> You can't block just a thread, since there is no "queue a
> lock request" interface, only a "try to get the lock, and
> return if you can't" or a "block and wait for the lock".
> 
> In other words, flock() is one call that can't really be
> reasonably implemented by the threads library, since
> there is no way to map it safely, and still guarantee
> against an order inversion deadlock.
> 
> 
> > > Also if you have shared memory, why not use
> > >
> > > /* Get a spin lock, handle recursion inline (as the less common case) */
> 
> 
> Using the "cmpxchgl" instruction is your best approach;
> I personally would not use the whole thing, as Julian
> suggested, since I think the SMP synchronization ops
> are much, much heavier than they should be.  You don't
> need that much overhead, you don't need reentrancy, and
> you don't need it to do counting (neither does SMP).
> 
> The easiest way to get shared memory is to use mmap() in
> both programs on a file, and to madvise() the caching and
> cache writeback off.  This is much beeter than SYSV shared
> memory (shmat, shmget, etc.), since it is properly resource
> tracked, and you will not have a startup order of operation
> problem, nor will you have the common problem of trying to
> get rid of the segments, should any of your programs exit
> abnormally.
> 
> > I'd rather have something portable though, and I would
> > still like to know if what I was doing should have worked...
> 
> The answer is "no".  Threads are not processes, they exist
> in a single process context, as they currently exist.  In
> the future, what you are doing will work, but will have a
> very high comparative overhead to other approaches.
> 
> If you read Stevens, you will see that flock() is much
> higher overhead than doing semop() calls.
> 
> To wrap either, you would need to:
> 
> retry:
> st = try_non_blocking_get();
> if (st == FAIL) {
> yield();
> goto retry;
> }
> 
> Note that the "yield" system call is non-standard, and you
> will buzz-loop somewhat, depressing your priority.  You
> will also have a race window, subject to the "thundering
> herd" problem.  You could put a "sleep(1);" in place of
> the "yield();" call... this would eliminate the buzzing
> (somewhat), but would widen the race window.
> 
> Another alternative is to use a multiended pipe, where
> you write a single character token down the pipe, and
> your programs block waiting for a single character read
> to complete (you could use a FIFO or socket, in place of
> the pipe).  The point is that only a single reader can
> get the character (the "token") at a time.
> 
> Unfortuantely, since file I/O is implemented as a
> conversion of a blocking call to a non-blocking call
> plus a context switch (normal for a threads library),
> you still have the "thundering herd" problem.
> 
> Further, if your intent was to have the callers serviced
> in the order they called the read, you can't: you will
> never have a guarantee about who will be permitted to
> complete the read first.
> 
> So, for FIFO ordering, there's no way for you to solve
> the problem; for semop or flock, you can solve the problem
> portably with a "sleep - retry" loop, and not burn too
> many cycles (but still lose FIFO ordering).
> 
> If you absolutely _must_ have a FIFO, then you need to
> either wait, or install the Linux threads port (Linux
> threads are hideously expensive, compared to the current
> FreeBSD threads implementation, since they effectively
> create a new process for each thread, just like Linux
> does), and use blocking operations using them.
> 
> Probably, if you need FIFO ordering, whatever you are
> doing would be better implemented as a finite state
> automaton, or a "work-to-do" model, where you don't
> really care who wins a race in a "thundering herd",
> since all of your programs waiting on the condition
> are identical.
> 
> Worse comes to worse, you should consider implementing
> your threads as real seperate processes (and not fake
> ones, like in the Linux threads library).
> 
> -- Terry
> 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?203501c11059$35755420$2964a8c0>