Tuesday, December 30, 2008

comp.programming.threads - 5 new messages in 2 topics - digest

comp.programming.threads
http://groups.google.com/group/comp.programming.threads?hl=en

comp.programming.threads@googlegroups.com

Today's topics:

* Why are Boost thread mutexes so slow compared to Pthreads? - 4 messages, 2
authors
http://groups.google.com/group/comp.programming.threads/t/9c9fd9b9ccafc16a?hl=en
* problem with pthread_cancel - 1 messages, 1 author
http://groups.google.com/group/comp.programming.threads/t/e3ae6dbb7de05a21?hl=en

==============================================================================
TOPIC: Why are Boost thread mutexes so slow compared to Pthreads?
http://groups.google.com/group/comp.programming.threads/t/9c9fd9b9ccafc16a?hl=en
==============================================================================

== 1 of 4 ==
Date: Mon, Dec 29 2008 10:03 pm
From: David Barrett-Lennard


On Dec 30, 12:52 pm, JC <jason.cipri...@gmail.com> wrote:
> On Dec 29, 10:01 pm, David Barrett-Lennard <davi...@iinet.net.au>
> wrote:
>
>
>
>
>
> > On Dec 30, 8:44 am, "Chris M. Thomasson" <n...@spam.invalid> wrote:
>
> > > "David Schwartz" <dav...@webmaster.com> wrote in message
>
> > >news:3d7403b4-4b25-4850-97c3-b572b19d1873@d42g2000prb.googlegroups.com...
> > > On Dec 29, 5:00 am, David Barrett-Lennard <davi...@iinet.net.au>
> > > wrote:
>
> > > > > It strikes me as messy and confusing that a lock object can continue
> > > > > to exist without actually holding a lock.
> > > > Then what do you do when some code uses a scoped lock holder and you
> > > > need to run a small piece of code inside that scope without holding
> > > > the lock? Do you re-architect the code completely?
>
> > > You can use a scoped unlock RAII helper object:
>
> > > static mutex g_mutex;
>
> > > void foo() {
> > > {
> > > scoped_lock lock(g_mutex);
>
> > > do_locked_stuff();
>
> > > {
> > > scoped_unlock unlock(g_mutex);
>
> > > do_unlocked_stuff();
>
> > > } // mutex.lock();
>
> > > do_more_locked_stuff();
>
> > > } // mutex.unlock();
>
> > > }
>
> > > [...]
>
> > This doesn't stop the fact that a lock object can exist yet a lock is
> > not actually held. Why are (procedural) programmers so quick to
> > defeat simple declarative truths?
>
> > One example of the pursuant damage: a scoped_lock no longer identifies
> > an atomic unit of work on the protected state.
>
> If you start off with a rule that "locks are held when a scoped_lock
> is in scope" then your rule may not be useful and you should change
> it.

But the rule *is* useful. It leads to the trivial correspondence
between lexical scopes and locks. If you mess with the rule then you
mess with the trivial correspondence.


> Note that the name "scoped_lock" is not a great name, perhaps
> renaming the object to something like "auto_lock" will make it more
> palatable.

Perhaps you would find auto_unlock even more palatable.

It appears you don't appreciate the declarative nature of a
scoped_lock. I like to read it as a declarative statement of
incontrovertible fact that the entire block of code shall always be
protected by a lock, and no code anywhere can do anything to change
that.


> In general, I've noticed that when programming, if one
> finds that something is philosophically incorrect, it is frequently
> one's philosophy that is incorrect.

So your philosophy must be to avoid having a philosophy :)


> > I would go as far as saying that a scoped_unlock class only exists to
> > create a lie in its now ugly brother. It is a hack! It is an example
> > of what you get when you only think procedurally.
>
> The code is semantically equivalent to your approach, which is also
> not a hack. Both are still exception safe, still 100% effective, clear
> to read, and present the same solution to the same problem (locking
> portions of code with automatic unlocking).

Oh yes at some level they are equivalent. However one maps much more
directly to simple logic. If you were to formalise the meaning of the
code in logic you would find my version to be much simpler.


> > It has added complexity and inconsistency and forces one to more
> > carefully read the code to understand where locks are actually in
> > place.
>
> It's not complex, and it is well-defined, consistent, and convenient.


Ok, have you considered arbitrary nestings of try-catch blocks,
scoped_locks and unscoped_locks. What are the rules? Eg is it
permissible to use an unscoped_lock at the outermost level? If not
does it cause an assertion in debug builds? Is it permissible for a
scoped_lock to be nested within an unscoped_lock? Are there any
surprises when an exception is thrown and the stack unwinds? What are
the efficiency repercussions? Are counters or bools required to keep
track of what's happening? If so where is this state stored? In
thread local storage?

What's an appropriate methodology to achieve code reuse when using
these scoped_locks and unscoped_locks? Is it based on somewhat
blindly factoring otherwise repeated code into functions, or are there
some rules of thumb that help? If one is following the principle of
design by contract, how does one carefully state contracts associated
with making used of these scoped_locks and unscoped_locks?

> I personally do not have to scrutinize that code (or your code)
> carefully to know exactly where locks are and are not held

I would hope so, the example was simple.


> , and would
> argue that it's more your unfamiliarity with the technique that causes
> the confusion rather than a flaw in the technique itself.

I had no trouble understanding the technique. My problem is with the
damage it would do if I used it in my own production code.


> In that
> case, becoming familiar with the technique is the easiest solution (it
> is a simple technique to learn), the second easiest solution is a
> simple one-word comment in the code. Neither solution is a major
> setback.

Part of the damage is collateral. It badly affects the way you think
and decompose problems.


> > Why not instead do this?
>
> > void foo()
> > {
> > {
> > scoped_lock lock(g_mutex);
> > do_locked_stuff();
> > }
>
> > do_unlocked_stuff();
>
> > {
> > scoped_lock lock(g_mutex);
> > do_more_locked_stuff();
> > }
>
> > }
>
> > This code is now logically coherent in its decomposition. The parts
> > are semantically meaningful. The parts are better decoupled. It is
> > far more likely that you parts are reusable in a different context.
>
> You are both wrong and sometimes right. You are right in that it is
> sometimes logically coherent and that the parts are sometimes
> semantically meaningful -- however, this all depends on the nature of
> the code.

I disagree. Doing stuff in a separate lock generally implies it is a
semantically meaningful chunk of work.

However my point was really that Chris's approach is incoherent in the
sense that on its face a scoped_lock appears to state that a lock is
held for the scope of the instance, and yet that is not actually the
case. As you said yourself, it needs a "better" (verbose) name,
associated with its much more complex semantic - including its curious
interaction with an unscoped_lock.

Let C = SEQ(C1,C2,C3) represent the result of executing C1 then C2
then C3. Chris's approach doesn't actually achieve that very powerful
and useful form of decomposition. There is increased coupling, and
less opportunity for code reuse.


> With Chris Thomasson's approach, deleting the unlocked
> portion of the code also removes the unlock itself, with your approach
> it does not. Using a scoped_unlock gives a completely isolated bit of
> code that can be removed without affecting the code around it. Of
> course, that also may not always be appropriate, but his approach is
> *also* sometimes logically coherent and sometimes semantically
> meaningful.
>
> However, you are wrong in that it is not necessarily the most
> convenient answer to your specific question, which was:
>
> > Then what do you do when some code uses a scoped lock holder and you
> > need to run a small piece of code inside that scope without holding
> > the lock? Do you re-architect the code completely?
>
> Your approach reorganized the existing code. Chris Thomasson's
> approach did not. Both your code and Chris's code are clear,
> meaningful, and effective, but in addition, Chris's solution is a more
> convenient solution.

Are you certain that Chris's solution involves less typing? In my
favourite editor adding braces and changing indentation is very fast.
Duplicating the line that gets the lock only requires copy and paste.
With Chris's solution I might want his comments to help the (poor)
reader understand what's happening.


> While both forms are just as effective, and equivalent, *if* the
> problem is to conveniently add an unlocked portion to existing code,
> *then* Chris's solution is better.

In the sense of a bandaid on a festering sore :)


> All that said, personally I don't think I would use scoped_unlock
> either; I would either stick to something closer to your form, or I
> may just add explicit lock / unlock to the scoped_lock instead (again
> renaming it to something more appropriate):
>
> void function () {
>
> lock_holder holder(g_mutex);
> do_locked_stuff();
>
> holder.release_lock();
> do_unlocked_stuff();
>
> holder.acquire_lock();
> do_more_locked_stuff();
>
> }


YUK!


> Or auto_lock, or scoped_lock, or lock/unlock or acquire/release, the
> choice is irrelevant. Defining a rule that says "acquire_lock when
> already acquired is a no-op, and the same for release_lock" could
> allow you to further group your code into logical, isolated parts,
> while still giving you the features of a scope-based automatic
> release. Whatever.

The best way to group your code into logical, isolated parts is to
design that way from the start and to recognise forms of decomposition
that have a simple basis in logic.

> That approach, your approach, and Chris Thomasson's approach are all
> semantically equivalent, all are easy to read, all are convenient to
> deal with, none deserve to be called a "hack".

I set high standards for myself and others :)


> Also note that the topic is now turning to how exactly to express an
> idea in C++. A somewhat more language-neutral description of the above
> would be:
>
> scope {
> lock g_mutex
> do locked stuff
> unlock g_mutex
> do unlocked stuff
> lock g_mutex
> do locked stuff
> (note: if we leave scope for *any* reason while g_mutex is locked,
> it is automatically unlocked).
>
> }

What syntactic device implies (other than a comment) that g_mutex is
automatically unlocked? You're not suggesting that 'lock g_mutex'
does that are you? Sometimes the purpose of a function is to acquire
a lock on behalf of its caller.

== 2 of 4 ==
Date: Mon, Dec 29 2008 10:30 pm
From: David Barrett-Lennard


On Dec 30, 2:17 pm, David Schwartz <dav...@webmaster.com> wrote:
> On Dec 29, 8:02 pm, David Barrett-Lennard <davi...@iinet.net.au>
> wrote:
>
>
>
>
>
> > I think your code can be put into a function as follows:
>
> > void AcquireLock(X& Object)
> > {
> > Object.Lock();
> > while(Object.IsNotReady())
> > {
> > waiter = Object.GetWaiter();
> > Object.Unlock();
> > waiter->WaitFor();
> > delete waiter;
> > Object.Lock();
> > }
>
> > }
>
> > It is now clear how this could be used to acquire the initial lock for
> > an instance of a lexically scoped lock.
>
> Except this will fail if the lock is already held.

Do you mean if the lock is already held by the calling thread? I
presume it's ok if there is a lock currently held by a different
thread.

> To call this
> function, you must 100% for certain know whether or not you hold the
> lock.

Yes, I see that because Unlock() may not actually release the lock
because of a counter of nested locks.

> Now, a very common situation is that you are in a function that
> you know can only be called with the lock not held and only returns
> with the lock not held.

Ok

> If there are destructors that release the
> lock, how do you reliably figure out whether or not you held the lock
> when you contemplate calling this code?

If you're within the scope of a lexical lock then you know you have a
lock so you wouldn't call this code.

I don't understand the problem. Can you provide a reference?


== 3 of 4 ==
Date: Mon, Dec 29 2008 10:57 pm
From: David Schwartz


On Dec 29, 10:30 pm, David Barrett-Lennard <davi...@iinet.net.au>
wrote:

> > If there are destructors that release the
> > lock, how do you reliably figure out whether or not you held the lock
> > when you contemplate calling this code?

> If you're within the scope of a lexical lock then you know you have a
> lock so you wouldn't call this code.

That is true if and only if the scope of the lexical lock is 100%
identical to the block. But as I explained, that's a hideously
deficient design pattern because it forces you into a procrustean
choice -- if you need to drop the lock inside the lexical scope, do
you re-architect the entire block and risk missing points that require
an unlock or do you use a sub-optimal solution that doesn't involve
dropping the lock?

> I don't understand the problem.  Can you provide a reference?

The problem is that if you force a lock to match a lexical scope, you
have to rearchitect if you need to do something inside that scope that
cannot be done while holding the lock. The other problem is that
because you don't see an 'unlock' at the '}', it's easy to miss the
fact that code before the '}' runs with different locks held than code
after the '}'.

And, again, the major problem is simply that an "can't forget to
unlock" abstraction is useless, because you always must restore
invariants precisely before you unlock. A helpfully-added forgotten
unlock will be disastrous if invariants are not restored. It's hard to
audit all unlock points to make sure that invariants are restored on
all of them because the abstraction deliberately hides unlock points.

For example, before calling any function that might throw an
exception, you have to restore invariants or catch the exception.
That's a bitch to debug/validate.

And finally, lexically scoped locks are horrible for beginning threads
programmers because they cause them not to think about exactly where
their unlocks should be placed. They tend to make the unlock somehow
subordinate to the lock. This isn't, strictly speaking, a defect in
lexically scoped locks, but it is a demonstrable fact that people who
use such automatic locking constructs learn to construct poor locking
schemes. They wind up calling code while holding a lock that should
not hold the lock simply because it is difficult to release the lock
where it needs to be released.

DS


== 4 of 4 ==
Date: Mon, Dec 29 2008 11:46 pm
From: David Barrett-Lennard


On Dec 30, 1:18 pm, JC <jason.cipri...@gmail.com> wrote:
> On Dec 29, 8:00 am, David Barrett-Lennard <davi...@iinet.net.au>
> wrote:
>
>
>
>
>
> > On Dec 29, 8:05 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
>
> > > Giancarlo Niccolai wrote:
> > > > Scoped locks are not evil by themselves. OTOH, scoped lock encourages
> > > > harmful practices in code that needs not to be subject to more harmful
> > > > practices than those it is usually already subject too.
>
> > > You seem to assume that scoped locks cannot be explicitly released
> > > (iow. they can only be released by them going out of scope).
>
> > > If you want to be able to release a lock early, then just add a member
> > > function for that purpose. I don't see the problem.
>
> > > What the automatic release does is that it makes your life easier. For
> > > example:
>
> > > int foo()
> > > {
> > > ScopedLock lock;
> > > if(error1) return 1;
> > > do_something();
> > > if(error2) return 2;
> > > do_something_else();
> > > if(error3) return 3;
> > > lock.release();
> > > do_some_unlocked_stuff();
> > > return 0;
> > > }
>
> > It strikes me as messy and confusing that a lock object can continue
> > to exist without actually holding a lock.
>
> In many situations, the rule that "if a lock object exists, it holds a
> lock" is unnecessary and overly limiting.

Yes, it limits your ability to write poorly structured code :)

> The existence of that rule
> causes you to feel uncomfortable when you have to work around the rule
> after finding that it is not appropriate.

Please provide an example to demonstrate that claim.

> It is better to not define
> that rule in the first place.

You must have a compelling reason to want to give up on the
simplifying notion that the scope of a lock precisely matches a
lexical scope. What is it?


> > <generic-rant>
>
> > I think many programmers tend to jump in and add flexibility to their
> > classes at a moments notice without realising the damage to their
> > design.
>
> While you have a point in general, that does not apply in the context
> of automatic lock holders. There is a difference between "adding
> flexibility at a moments notice" and "designing your class to be
> flexible to begin with".

Adding that flexibility kills the strong declarative reading of the
construct.


> If you designed an automatic lock holder using your rule that "if the
> object exists, it holds a lock", then your design is actually only
> useful for the most trivial situations. Because of that rule and the
> design based around it, you are *forced* to "jump in and add
> flexibility" when you realize the mistake.

I have used lexical locks without a release method for years, and have
never felt the need to "jump in and add flexibility".


> On the other hand, if you design an automatic lock holder correctly in
> the first place, it is neither messy nor confusing. For example, in C+
> +:
>
> // this object provides a means to acquire and release a
> // lock, automatically releasing an acquired lock when
> // this goes out of scope.
> class lock_holder {
>
> public:
>
> // constructor will acquire the mutex lock
> lock_holder (mutex &m);
>
> // destructor will release the mutex lock if acquired
> ~lock_holder ();
>
> // release the lock, no-op if not acquired
> void release_lock ();
>
> // acquire the lock, no-op if already acquired
> void acquire_lock ();
>
> };
>
> There, it was done correctly from the start, and is useful in a far
> wider range of scenarios without being messy or confusing.

While you're about it, why not add an is_locked() method?

It's indeed flexible. Unfortunately it loses more than it gains. It
forces you to more carefully read the code to understand the scope of
a lock. It fails to highlight the atomic units of work on the
protected state. It allows the programmer to easily make the scope of
locks complicated (eg with conditional tests for when to release and
acquire locks). Even the no-ops invite hiding of redundant statements
or errors.

On a minor note, it is also less likely that the object on the frame
will be compiled out of existence because of the bool member that is
tested in the destructor. Of course this may not be a problem for
many compilers.


> > If one is after clarity then for a start one should strive for the
> > principle that one can think of a relatively simple name of a class
> > that accurately tells exactly how it behaves. I don't get that
> > feeling at all with the above ScopedLock class.
>
> ScopedLock is a poor name for it.

lock_holder is better?

> > I don't like the release method. I don't believe it should exist. If
> > anything in this thread could be called "evil" then I think the
> > release method is a good candidate.
>
> This is because it violates the broken rule that you defined earlier.
> The reason you defined said broken rule may very well be because
> either A) "ScopedLock" was a poor choice for the name, or B) a pure
> "scope-based" lock was the wrong tool for the job. A and B are mostly
> equivalent, the difference is inconsequential and is only how you
> prefer to look at it.

If the name fits good. More important of course is whether it's a
simple, useful, powerful building block.

> > </generic-rant>
>
> > The following removes a line of code and makes the scope of the lock
> > visually obvious:
>
> > int foo()
> > {
> > {
> > ScopedLock lock;
> > if(error1) return 1;
> > do_something();
> > if(error2) return 2;
> > do_something_else();
> > if(error3) return 3;
> > }
> > do_some_unlocked_stuff();
> > return 0;
>
> > }
>
> > Isn't it better for it to always be the case that the lock protects
> > all code that falls within the scope of the ScopedLock? Why make
> > something declarative into something procedural? Why make a construct
> > with a trivial mathematical definition into something more complex,
> > invites inconsistent usage and hurts readability? Why defeat the
> > whole purpose which was to create a trivial association between a
> > lexical scope and a lock?
>
> It does not matter; see my response to you else-thread. In your case,
> a "scoped" lock is not what you want. In any case, this:
>
> int function () {
> {
> SomeAutomaticLockHolder lock;
> if(error1) return 1;
> do_something();
> if(error2) return 2;
> do_something_else();
> if(error3) return 3;
> }
> do_some_unlocked_stuff();
> return 0;
>
> }
>
> And this:
>
> int function () {
> SomeAutomaticLockHolder lock;
> if(error1) return 1;
> do_something();
> if(error2) return 2;
> do_something_else();
> if(error3) return 3;
> lock.release();
> do_some_unlocked_stuff();
> return 0;
>
> }
>
> Are semantically identical. Which one you use is irrelevant and is
> only a matter of whether or not you've provided an explicit release
> with your lock holder implementation -- and whether or not you've done
> that has no bearing on the usefulness of automatic lock holders in
> general, in any similar language.

What is the relevance of this equivalence? Do you claim in general
that all different ways of writing the same program are equally
good? If not what point are you making here?


==============================================================================
TOPIC: problem with pthread_cancel
http://groups.google.com/group/comp.programming.threads/t/e3ae6dbb7de05a21?hl=en
==============================================================================

== 1 of 1 ==
Date: Mon, Dec 29 2008 11:02 pm
From: David Schwartz


On Dec 29, 9:28 pm, vamsi <vamsi.kom...@gmail.com> wrote:

>     I have an application where it creates 32 threads. Later in the
> logic, it has to kill some 10 threads. All the 10 threads does a
> recvfrom on a unique socket in a while loop. To cancel the thread,
> pthread_cancel API is used to send a cancel signal to the target
> thread from the main thread, from which threads got created. All the
> threads are initialized as canceltype - asynchronous. The
> pthread_cancel API sends signal to 8 threads succesfully, however for
> the 9th thread the pthread_cancel fails with an error number 11
> (EAGAIN).

My bet is that you have made one of three mistakes:

1) While your cancel state is set to asynchronous, you have called a
function that is not cancel-safe. You cannot call any functions that
are not cancel-safe while your cancellation state is set to
asynchronous.

2) You have misdiagnosed the returned error number. (Did you check
'errno'? That's a mistake as 'pthread_cancel' returns the error code
and does not set 'errno'.)

3) Your thread has actually terminated or was detached. As a result,
the pthread_t is not valid.

DS

==============================================================================

You received this message because you are subscribed to the Google Groups "comp.programming.threads"
group.

To post to this group, visit http://groups.google.com/group/comp.programming.threads?hl=en

To unsubscribe from this group, send email to comp.programming.threads+unsubscribe@googlegroups.com

To change the way you get mail from this group, visit:
http://groups.google.com/group/comp.programming.threads/subscribe?hl=en

To report abuse, send email explaining the problem to abuse@googlegroups.com

==============================================================================
Google Groups: http://groups.google.com/?hl=en

No comments: