Le 26/07/14 19:34, Ian Forbes a écrit :
Your queue is flawed: what if T's copy constructor is invoked when calling pull(), and it throws an exception? Also, pull() is conventionally called "pop". I can't see anyway around this as the queue needs to be locked to guarantee serial execution to top() and pop(). The convention of having top() and pop() to avoid this can't be used since a call to top() followed by a call to pop() on the same thread are no guaranteed to happen consecutively.
One solution would be have T top(mutex* p) that would accept a mutex pointer and store the internal queue's mutex address into this. The method would lock the queue but would not unlock it. Then we could have void pop(mutex* p) that would take that mutex pointer and unlock it after the pop. Users could either unlock mutex after top or pass it to pop to unlock for them. This however is a fairly poor solution since an uncaught copy ctor would cause the queue to be locked forever.
mutex* m; T copy = queue.top(m); //Queue is now locked. If T's copy ctor throws we have to unlock the mutex, otherwise deadlock. queue.pop(m); //A call to pop will unlock the mutex through m.
If you have another solution please provide it. Also see Vicente's comments on this as well.
Your solution is not as simple as it could be. A possible solution consists in adding functions having an additional lock as parameter uniqye_lock<mutex> lk(queue.mutex()); T copy = queue.top(lk); queue.pop(lk); An alternative is to provide a way to get an externally_locked of the underlying queue. externally_lockedstd::queue q(queue.get()); T copy = q.top(lk); q.pop(lk); You can see the section external locking in Boost.Thread documentation We could always provide an external locking interface on lock based queues, but not for lock-free ones. Best, Vicente