BIND 10 #2332: define and implement wrapper interface for conditional variables

BIND 10 Development do-not-reply at isc.org
Wed Oct 10 17:32:52 UTC 2012


#2332: define and implement wrapper interface for conditional variables
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:
  jinmei                             |                Status:  new
                       Type:  task   |             Milestone:
                   Priority:         |  Sprint-20121023
  medium                             |            Resolution:
                  Component:         |             Sensitive:  0
  b10-auth                           |           Sub-Project:  DNS
                   Keywords:         |  Estimated Difficulty:  5
            Defect Severity:  N/A    |           Total Hours:  0
Feature Depending on Ticket:         |
  background zone loading            |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by jinmei):

 Replying to [comment:7 vorner]:

 > Are there two mutexes in the game (internal and the passed to wait) or
 just
 > one? If just one, how does the caller lock? If two, how do they
 interact? And

 There are two mutexs: one within `CondVar` (hidden from others), the
 other passed to `CondVar::wait()`.  The former controls that the lock
 for the latter will be held immediately before the thread sleeps on
 `CondVar` (and prevent deadlock situation).  The latter is used to
 protect some other data.  btw, this design is derived from
 boost::condition_variable (but much simplified).

 > if they interact, is it guaranteed to be race-condition-free and
 deadlock-free?
 > Don't forget, the mutex is not for the protection of the condition
 variable, it
 > is for the shared state around it. The whole trick with condvars is that
 the
 > wait unlocks the mutex protecting the data atomically. Also, can
 multiple
 > threads wait on the same condition variable? I'm not saying your
 approach is
 > necessarily wrong, but it's not obvious it works and would need some
 kind of
 > proof.

 I understand these.  The second mutex (passed to wait()) is for the
 shared state around the condvar.  The internal mutex within `CondVar`
 is a tool only needed within `CondVar` to provide compatible interface
 as pthread_cond_wait().

 The question on race condition and deadlocks is valid.  I thought
 about it and concluded it was safe, but as always for thread related
 things I admit it's quite possible I still miss something.

 > Also, you don't need to lock for signal, it's save in either state of
 the mutex
 > (in my understanding, there's only difference in performance and it is
 case by
 > case dependant on which mode of operation is faster).

 I understand this too.  That applies to the second mutex (passed to
 wait()).  The mutex within `CondVar` needs to be held for the internal
 purpose of of the `CondVar` implementation (without this a deadlock
 can happen).

 > But what scares me is the shared pointer with the locker. The locker is
 meant
 > to be generally allocated on stack, for obvious reasons. The approach
 with
 > dynamic allocation has disadvantages in both less convenient operation
 and
 > being more error-prone. I think you're trading this in favor of not
 having a
 > friend declaration. I'd rather have the complexity hidden inside than
 passing
 > it onto the caller.

 I understand the use of the (shared) pointer is scary.  But my main
 reason for the use of it is to avoid making `Mutex::(un)lock`
 completely public to applications (which itself was not part of my
 design but I thought that was a design concept of the `Mutex` class),
 not to avoid making `CondVar` a friend of `Mutex`.

 Consider how we use the condition variable in our "data source
 configurator" thread.  Conceptually it would look like this:

 {{{#!cpp
 void
 run() {
     // some kind of mutex to protect the command queue, shared with the
 main
     // thread.
     Mutex mutex;
     CondVar condvar;            // shared with the main thread

     while (true) {
         mutex.lock();
         while (queue.empty()) {
             condvar.wait();
         }
         // at this point mutex is locked and queue is not empty
         command = queue.pop();
         mutex.unlock(); // release it as the following would be time
 consuming

         // do something based on command: reload a zone, reconfigure
 entire
         // data source clients, or shutdown the thread, etc.
     }
 }
 }}}

 But we cannot use our `util::Mutex` directly as `Mutex` in the above
 conceptual code because in our version lock() and unlock() are private
 methods.  It also didn't seem to be easy to use `Mutex::Locker` in the
 above scenario because, just as you mentioned, it would normally be
 instantiated on stack.

 I didn't think it possible to resolve this situation through making
 `CondVar` a friend of `Mutex`, hence the introduction of pointer to
 `Locker`.  With that introduction `CondVar` simply didn't have to be a
 friend of `Mutex`, and that's why I didn't make it so.

 I see the concerns you had in this proposal, and I don't think this
 one is the best one in terms of complexity and understandability.  If
 there's a design to make it possible in a safe and more
 understandable, I'm happy to use it.  Do you have a concrete proposal?

 And, one more thing: I also tend to agree that using `Locker` through
 a pointer could be considered a kind of abuse, but if so, I think the
 documentation should state that more clearly.  It currently reads:

 {{{#!cpp
     /// If you create the locker on the stack or using some other "garbage
     /// collecting" mechanism (auto_ptr, for example), it ensures
 exception
     /// safety with regards to the mutex - it'll get released on the exit
     /// of function no matter by what means.
 }}}

 This looks like it's actually expected to be used through auto_ptr,
 even though it's not explicitly encouraged.  If such usage is rather
 discouraged IMO we should say something like "even if something like
 this is possible, it's generally discouraged".

-- 
Ticket URL: <http://bind10.isc.org/ticket/2332#comment:8>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list