
John Fuller <jfuller@wernervas.com> writes:
On Feb 13, 2004, at 2:23 AM, Vladimir Prus wrote:
John Fuller wrote:
both Ted Yuan's producer-consumer templates (cujjan2004) and the synchronized template at http://libcalc.sourceforge.net/synchronized.hpp are nice thread-safe container implementations...
I could not find the first reference. Looking at the second, it seems to implement the same idea as Raoul Gough's presented. And of course, I'll ask the same question: if I have code like
if (!proxy->empty()) { int value = proxy->front(); //.... }
what prevents other thread from extracting all elements between the two calls? You're right about synchronized<> as far as containers are concerned.
Here's Ted Yuan's ProducerConsumer code from CUJ Jan '04 which does explicitly lock around these cases (ex: in offer and poll calls for a channel (a template wrapper for a container type)).
This code uses a lot of reserved names (starting underscore upper-case letter) which is interesting. I can only assume the CUJ isn't too bothered by that kind of stuff.
#ifndef _PRO_CON_H #define _PRO_CON_H
// // Copyright (c) 2002 by Ted T. Yuan. // // Permission is granted to use this code without restriction as // long as this copyright notice appears in all source files. //
[snip]
// for producer thread... bool offer(_Tp item, long msecs = -1) // ignore msecs for now { Lock lk(monitor_); while (maxSize_ == ((_queueTp *)this)->size()) { bufferNotFull_.wait(lk); }
// push front push(item); bufferNotEmpty_.notify_one(); return true; }
The only problem with this approach is that you have to acquire and release the lock for every operation (e.g. each call to "offer" only inserts one object). By using an external proxy object, it is possible to grab the lock, check how much space is available and shutgun a bunch of stuff into the queue in one go: { Queue::proxy_type const &proxy (gQueuePtr->getProxy()); proxy.blockOnFull (timeout); // Queue::sUnlimitedTime); while (!proxy.full()) { proxy->push_back (something_or_other); // ... } } I guess it opens up the possibilities for misuse as well. BTW, the proxy destructor does a notify_one or notify_all by checking for changes in the size of container during its existence. This adds some complexity, of course, and might be a problem with std::list. -- Raoul Gough. export LESS='-X'