Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-03-26 19:05:09


--- In boost_at_y..., Jens Maurer <Jens.Maurer_at_g...> wrote:
> williamkempf_at_h... wrote:
> > [Jens Maurer wrote:]

> [ Interfaces vs. performance]
> > Unless you think the interface prevents creating
> > efficient implementations
>
> So I believe.

That wasn't clear in your first post. Care to elaborate?

> > > Also note that the pimpl-wrapping in boost::fast_mutex costs
about
> > > 10% performance.
> >
> > I don't see this evidenced in your timings above. How did you
figure
> > this out?
>
> Your fast_mutex takes 0.25 usec, even the slowest native mutex
> takes only 0.22 usec. That's about 10% (or even more) of a
difference
> to me.

There's no evidence that pimpl causes this, however. There are other
factors involved. The only real test would be to run timings for
both pimpl and non-pimpl.
 
> > You must not be looking at the latest upload, which makes me
question
> > your timings above. The implementation changed drastically for
> > pthreads and so they may (likely will) run much faster if you
truly
> > were using an older implementation. As for bool conversions,
they've
> > long since been replaced by void* conversions.
>
> I'm confused. I've looked at
> http://groups.yahoo.com/group/boost/files/threads/threads.zip
> dated 2001-03-22, size 62080 bytes, which seems to be the latest
> as of this writing. boost/thread/xlock.hpp contains three operator
bool()
> functions.

Ok, let me check this out later tonight just to be sure of what's
going on. The bool conversions were changed to void* conversions at
least to uploads ago, so I'm not sure what's going on. I'll get back
to you on this one.
 
> > > - The timedlock interface (milliseconds) should be changed to
> > > the equivalent of POSIX timespec, i.e. seconds and nanoseconds
to
> > > be future-safe.
> >
> > A) I very much dislike using a "time out at a specified time"
> > implementation preferring to "time out after a specified
duration".
>
> Sorry, I should have been more descriptive: I mean the "time out
after
> a specified duration" semantics are what they should be. However,
> I advocate using seconds and nanoseconds to specify the duration.
> Since the largest portable datatype is long (32 bits min.
guaranteed),
> we need to split the duration into a "long" for the nanosecond
> (fractional) part of the duration and another "long" for the seconds
> part. I mentioned "timespec" for exposition of the kind of
> description for the timeout.

In C++ I wouldn't pass a structure for this. I'd pass two longs.
That aside, this is not totally unreasonable, excepting the next
point.
 
> > C) It might be possible to define the waits in terms of seconds
and
> > nanoseconds, the basic options available with timespec, but not
all
> > platforms support this fine a grain of time duration.
Milliseconds
> > are more likely to be implementable on multiple platforms. This
was
> > the reasoning chosen at the time these interfaces were designed,
but
> > I'm not locked into this.
>
> My reasoning is that the interface should not preclude more
> precise timeouts. It should be implementation-defined what the
> internal resolution of timeouts is (i.e. every platforms defines
> the resolution). We can have a general "at least microseconds
> resolution is available everywhere" clause, but this is incorrect
on
> Linux/x86 at least which only has 100 Hz scheduling frequency.

Reasonable, and I'll definately consider this change. What I'm not
sure about is when such precision would ever be useful, but that's
not a good argument against.
 
> > > - atomic_t should say that value_type must be at least "int".
> > > Otherwise, it's of not much use in the real world.
> >
> > I'm not sure I follow you here. Care to explain?
>
> According to my reading, atomic_t's value_type is
> "implementation defined", with no restriction on what the type may
> be.

It needs to be integral. I can make that requirement better stated.

> So it could be a "bool", seriously limiting the portable
> use of atomic_t, because the portable assumptions I can make
> on atomic_t are rather limited. If you say it's at least an "int" ,
> I can be sure it's 15 bits at least (guaranteed by the C++
standard).

I'm not sure that that's appropriate. That's why I asked you to
explain. It might be that an implementation needs to use short in
order to get hardware supported atomic operations (yes, I know this
is extremely unlikely since int's are supposed to be the preferred
platforms integer size). In reality I'd expect all implementations
to use int, but should the documentation be so rigid as to preclude
short from use for instance?
 
> > > - How do I put a variable number of mutexes in a dynamic data
> > > structure? Say, I'd like to implement the "dining philosophers"
> > > problem with a runtime configurable number of philosophers?
> >
> > I don't see the problem here either.
>
> I don't remember all the details of the dining philosophers'
problem,
> but here's my current interpretation: There are n philosophers
around
> a round table, with n forks between them. There's a plate with
> an unlimited amount of spaghetti in front of each philosopher,
> but any philosopher needs the fork to its right *and* the one
> to its left to start eating. A philosopher can decide to stop
> eating (and return the forks) for a while. Everyone should have a
> chance to eat once in a while. Assume there's no global
> coordination (e.g. numbering the philosophers and having the
> even numbered ones eat first and then the odd numbered ones and
> so on).

I'm familiar with dining philosophers. In fact, starve_phil is a
variation on this classic problem. What I didn't understand was what
you thought was difficult to do with Boost.Threads while solving this
problem.
 
> For a trivial (possibly deadlock-prone) solution, I'd like to have
> a std::vector<mutex>, one mutex for each fork (a fork is a shared
> resource and thus needs to be protected). However, a mutex is
> noncopyable and thus not usable in a standard container.

So, you're problem has nothing to do with "How do I put a variable
number of mutexes in a dynamic data structure" (at least as I read
that) but with how you can store these types in a standard
container. The solution is no different than how you'd do it with
any noncopyable type... allocate it on the heap, probably controlled
by a wrapper such as shared_ptr. I'm not sure that something like
this deserves explicit documentation, though I can certainly do so.

> Here's the conceptual question: How can I have a runtime-
configurable
> amount of mutexes (here: representing forks)? (No, I don't want
> to allocate these with "new" manually. Too tedious and error-
prone.)

Neither tedious nor error prone when properly wrapped (which may not
mean wrapped with shared_ptr).

It seems to me that what you're really getting at is that you'd
prefer the types to be copyable. This opens up a huge can of worms.
It was considered and rejected.
 
> > The only define really used outside of compiling Boost.Threads
for a
> > given platform is BOOST_HAS_THREADS. I imagine the other defines
> > could be specified by the build process instead of being placed
in a
> > header at all.
>
> Ok, so we don't expand config.hpp, but have a threads-private header
> for the threads configuration, while we're waiting for the boost
build
> system to happen. (No need to depend on vaporware).

Or the needed defines are just part of the multitude of
makefiles/project files supplied for building. This would probably
be easier than the header approach, whether the header is config.hpp
or threads/config.hpp.
 
> > I don't think we should use additional headers. Either specify
these
> > at build time, or leave them in config.hpp. Defining a new header
> > for this is only going to complicate things for users.
>
> Why? The user (of the boost library) never has anything to do with
> these defines (and, in an ideal world, should have no business
> with defines in config.hpp).

I'm looking at it from the implementors stand point, not the final
end users. Sorry, I didn't state that very well. Any of the three
solutions will be transparent (mostly, any way) for the end users.
 
> So having a new header will just clearly separate compiler/library
> issues from OS/hardware things. For example, implementing atomic_t
> on Linux will need to be done from scratch (as far as I can see
> at the moment), so it's very much CPU dependent.

That's why I think it's better to do it in the build system. Hacking
any header for this level of information is going to be very
difficult to do given the little bit of info available to the
compiler.

Bill Kempf


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk