Subj : Re: condvar wait / signal on arbitrary object To : comp.programming.threads From : Michael B Allen Date : Tue Jul 12 2005 10:58 pm On Tue, 12 Jul 2005 15:09:09 -0400, Eric Sosman wrote: > Michael B Allen wrote: >> I just had a thought and I'd like your opinion. >> >> Instead of embedding a condition variable in each object one would want >> to wait and signal on, the object could be used as a key to lookup a >> condvar by it's address modulo the size of an array of convars. This has >> the benifit of permitting one to wait on an arbitrary object (like Java >> except you can specify the mutex to unlock). For example: >> >> #define CONDVAR_ARRAY_SIZE 17 >> >> struct ctx { >> pthread_cond_t array[CONDVAR_ARRAY_SIZE]; >> }; >> >> int >> ctx_pthread_cond_wait(struct ctx *ctx, void *obj, pthread_mutex_t *mutex) >> { >> pthread_cond_t *cond = ctx->array[(size_t)obj % CONDVAR_ARRAY_SIZE]; >> return pthread_cond_wait(cond, mutex); >> } >> int >> ctx_pthread_cond_signal(struct ctx *ctx, void *obj, pthread_mutex_t *mutex) >> { >> pthread_cond_t *cond = ctx->array[(size_t)obj % CONDVAR_ARRAY_SIZE]; >> return pthread_cond_broadcast(cond); >> } >> >> Of course depending on the table size there could be many spurious wakeups. >> >> What do you think? Good idea or should I not bother? > > What problem are you trying to solve? No problem in particular. It's just a little be cleaner perhaps. This is especially true during development because you're not modify structs and their (de)constructors. When you have solidified the object model you can then properly refit high-traffic objects with their own condvars. It also tests the validity of your condvar conditions with the extra spurious wakeups (although I would hardly call that a "feature" :-). > I've seen this technique used in a situation where there > were very many very short-lived objects created and destroyed > so rapidly that the overhead of pthread_cond_init()/destroy() > was undesirable. (One wonders why these transient objects > needed their own private condvars to begin with -- but strange > artifacts often creep in when existing single-threaded code is > "retrofitted" for multi-threading that wasn't envisioned in the > original design.) The drawback, as you note, is that signals > get replaced by broadcasts. > > One other thing: Since a condvar can only be associated with > one mutex at a time, it'd be an error if two threads used two > different mutexes to wait on two different objects that just > happened to map to the same condvar. Ahh, good point. > Perhaps an easy way to > dodge this would be to put the mutex in the `struct ctx' and > eliminate the `*mutex' argument from both functions. (In fact, > it serves no purpose in ctx_pthread_cond_signal() as things > now stand.) Or (I'm not certain that this actually makes sense but ...) each condvar could have its own mutex. struct ctx { pthread_cond_t condvars[CTX_ARRAY_SIZE]; pthread_mutex_t mutexes[CTX_ARRAY_SIZE]; }; ... int ctx_pthread_cond_wait(struct ctx *ctx, void *obj) { int idx = (size_t)obj % CTX_ARRAY_SIZE; pthread_cond_t *cond = ctx->condvars[idx]; pthread_mutex_t *mutex = ctx->mutexes[idx]; return pthread_cond_wait(cond, mutex); } Thanks, Mike .