[lockfree] Faulty (?) static assert

Hey, The lockfree::queue constructors raise a static assert if no capacity is specified. This contradicts the member initialization code close to the assert, for instance: queue(void): head_(tagged_node_handle(0, 0)), tail_(tagged_node_handle(0, 0)), pool(node_allocator(), has_capacity ? capacity : 0) { BOOST_STATIC_ASSERT(has_capacity); initialize(); } which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size. Would changing this to queue(void): head_(tagged_node_handle(0, 0)), tail_(tagged_node_handle(0, 0)), pool(node_allocator(), has_capacity ? capacity : 0) { BOOST_STATIC_ASSERT(has_capacity || capacity); initialize(); } reflect the actual intention? Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu

hello hartmut,
The lockfree::queue constructors raise a static assert if no capacity is specified. This contradicts the member initialization code close to the assert, for instance:
queue(void): head_(tagged_node_handle(0, 0)), tail_(tagged_node_handle(0, 0)), pool(node_allocator(), has_capacity ? capacity : 0) { BOOST_STATIC_ASSERT(has_capacity); initialize(); }
which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed. cheers, tim

Hey Tim,
The lockfree::queue constructors raise a static assert if no capacity is specified. This contradicts the member initialization code close to the assert, for instance:
queue(void): head_(tagged_node_handle(0, 0)), tail_(tagged_node_handle(0, 0)), pool(node_allocator(), has_capacity ? capacity : 0) { BOOST_STATIC_ASSERT(has_capacity); initialize(); }
which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed.
Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case. Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu

which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed.
Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed-sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list. cheers, tim

Tim,
which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed.
Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed- sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list.
In this case, I'd suggest converting the compile-time asserts into run-time asserts as all non-templated constructors are always instantiated regardless whether they will be called or not. Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu

Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed- sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list.
In this case, I'd suggest converting the compile-time asserts into run-time asserts as all non-templated constructors are always instantiated regardless whether they will be called or not.
hm, good point. will adapt the code

Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed- sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list.
In this case, I'd suggest converting the compile-time asserts into run-time asserts as all non-templated constructors are always instantiated regardless whether they will be called or not.
hm, good point. will adapt the code
FWIW, the attached patch fixes this. Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu

Tim,
which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed.
Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed- sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list.
I still don't understand why I shouldn't be allowed to default construct a queue with fixed_size<false> and without specifying a capacity. Why do I need to pass an initial number of nodes to the constructor in this case? Regards Hartmut --------------- http://boost-spirit.com http://stellar.cct.lsu.edu

which implies that 'has_capacity' is allowed to be false. From what I can see 'has_capacity' could be false, indeed, in particular if the queue is not bounded in size.
the idea is that the default constructor is only allowed, when the capacity is set at compile-time. otherwise the data structure won't be completely lockfree, as creating new nodes will hit the memory allocator. so the assertion is correct, but the initialization of the pool can be changed.
Hmmm, I do not understand. If the queue is constructed with fixed_size<false> (which is the default), this assertion will _always_ fire as you're not required to specify a capacity in this case.
that's the purpose of this assertion. if the data structure is not fixed- sized, you should use the explicit queue(int capacity) constructor in order to populate the free-list.
I still don't understand why I shouldn't be allowed to default construct a queue with fixed_size<false> and without specifying a capacity. Why do I need to pass an initial number of nodes to the constructor in this case?
while it is technically ok to allocate a queue with an empty freelist, this queue won't be lockfree, as the first enqueue operations will hit the memory allocator. with this API, i'm trying to encourage users to reserve enough space for their use cases. tim
participants (2)
-
Hartmut Kaiser
-
Tim Blechmann