why lockfree/queue.hpp requires has_trivial_assign and has_trivial_destructor to template type T
hi, all,as new to boost, i am looking for a solution to combine boost::lockfree::queue with std::function, i.e. boot::lockfree::queuestd::function, but unfortunately, the implementation of the lockfree queue required the T to be trivial assignable and trivial destructible.with some basic investigation to the implementation of boost::lockfree::queue, the assignment operator is using when pop or unsynchronized_pop, it calls detail::copy_payload, which is using operator= or constructor and operator=. though overloaded assignment operator may use more time and cause the pop function to wait for longer time, i do not see it would block the logic.for the destruction, queue implementation always calls pool.template destruct instead deallocate, which means even for a default destructor, it will also be called. so is this a defect or by-design behavior of the lockfree queue? thank you in advanced. .Hzj_jie
p.s. i am using boost 1.55 official release. but in boost 1.56, lockfree queue also has the same requirement. .Hzj_jie From: hzj_jie@hotmail.com To: boost-users@lists.boost.org Subject: why lockfree/queue.hpp requires has_trivial_assign and has_trivial_destructor to template type T Date: Mon, 4 Aug 2014 09:39:36 +0000 hi, all,as new to boost, i am looking for a solution to combine boost::lockfree::queue with std::function, i.e. boot::lockfree::queuestd::function, but unfortunately, the implementation of the lockfree queue required the T to be trivial assignable and trivial destructible.with some basic investigation to the implementation of boost::lockfree::queue, the assignment operator is using when pop or unsynchronized_pop, it calls detail::copy_payload, which is using operator= or constructor and operator=. though overloaded assignment operator may use more time and cause the pop function to wait for longer time, i do not see it would block the logic.for the destruction, queue implementation always calls pool.template destruct instead deallocate, which means even for a default destructor, it will also be called. so is this a defect or by-design behavior of the lockfree queue? thank you in advanced. .Hzj_jie
On 4/08/2014 21:39, 何子杰Hzj_jie wrote:
as new to boost, i am looking for a solution to combine boost::lockfree::queue with std::function, i.e. boot::lockfree::queuestd::function, but unfortunately, the implementation of the lockfree queue required the T to be trivial assignable and trivial destructible. with some basic investigation to the implementation of boost::lockfree::queue, the assignment operator is using when pop or unsynchronized_pop, it calls detail::copy_payload, which is using operator= or constructor and operator=. though overloaded assignment operator may use more time and cause the pop function to wait for longer time, i do not see it would block the logic. for the destruction, queue implementation always calls pool.template destruct instead deallocate, which means even for a default destructor, it will also be called.
so is this a defect or by-design behavior of the lockfree queue?
I asked the same question a while ago; it's by design. I don't recall the exact specifics, but I think the issue is that there are some cases when the payload object can be destroyed twice or copied after being destroyed, which can only be safe if the object has those trivial properties. A bare pointer does have those trivial properties, so if you don't mind additional allocation/deallocation on push/pop you can store a function<>* instead of the function<> itself. (There are ways to make lockfree queues that don't have to require these properties, but typically you have to sacrifice some flexibility, eg. MPSC instead of MPMC.)
thank you for the information Gavin.it looks like an implementation limitation to me. the pointer surely works, but it will cause trouble about the instance lifetime. my scenario is a threadpool, which will work on functions / lambdas [function
To: boost-users@lists.boost.org From: gavinl@compacsort.com Date: Tue, 5 Aug 2014 10:42:27 +1200 Subject: Re: [Boost-users] why lockfree/queue.hpp requires has_trivial_assign and has_trivial_destructor to template type T
On 4/08/2014 21:39, 何子杰Hzj_jie wrote:
as new to boost, i am looking for a solution to combine boost::lockfree::queue with std::function, i.e. boot::lockfree::queuestd::function, but unfortunately, the implementation of the lockfree queue required the T to be trivial assignable and trivial destructible. with some basic investigation to the implementation of boost::lockfree::queue, the assignment operator is using when pop or unsynchronized_pop, it calls detail::copy_payload, which is using operator= or constructor and operator=. though overloaded assignment operator may use more time and cause the pop function to wait for longer time, i do not see it would block the logic. for the destruction, queue implementation always calls pool.template destruct instead deallocate, which means even for a default destructor, it will also be called.
so is this a defect or by-design behavior of the lockfree queue?
I asked the same question a while ago; it's by design.
I don't recall the exact specifics, but I think the issue is that there are some cases when the payload object can be destroyed twice or copied after being destroyed, which can only be safe if the object has those trivial properties.
A bare pointer does have those trivial properties, so if you don't mind additional allocation/deallocation on push/pop you can store a function<>* instead of the function<> itself.
(There are ways to make lockfree queues that don't have to require these properties, but typically you have to sacrifice some flexibility, eg. MPSC instead of MPMC.)
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On 08/05/2014 08:48 AM, 何子杰Hzj_jie wrote:
it looks like an implementation limitation to me. the pointer surely works, but it will cause trouble about the instance lifetime. my
I believe that the limitation is inherited from atomic<>. If it is any consolation, there is ongoing work to allow smart pointers in atomic<>: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4058.pdf
scenario is a threadpool, which will work on functions / lambdas [function
], so let the threadpool queue keeps the instances would be an easy approach. but multi-produce-multi-consume is required.
By only having the next available thread listening on the consumer side you can reduce this to MCSP. See the Leader/Followers architectural pattern on how this can be done (but do notice that the threadpool has locks) http://www.cs.wustl.edu/~schmidt/PDF/lf.pdf
On 5/08/2014 18:48, 何子杰Hzj_jie wrote:
it looks like an implementation limitation to me. the pointer surely works, but it will cause trouble about the instance lifetime.
It's not that much trouble. Allocate the pointer when you enqueue (delete it if the enqueue fails) and pass it to std::unique_ptr as soon as it dequeues. The only other thing to remember is to dequeue and delete anything remaining in the queue in the destructor. (You may want to raise an error or something in this case anyway, as it means some tasks didn't get executed.)
my scenario is a threadpool, which will work on functions / lambdas [function
], so let the threadpool queue keeps the instances would be an easy approach. but multi-produce-multi-consume is required.
If you're not wedded to lock-free, you might want to look at Boost.Asio. It's lock-based but it's trivial to create a generic threadpool around its io_service, and it's very well optimised. I have created a lock-free mini-io_service for some of my own code but it's quite specialised and not really intended for general use.
participants (3)
-
Bjorn Reese
-
Gavin Lambert
-
何子杰Hzj_jie