Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
FORMUS3IC_LAS3
/
embb
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
acb6cf6b
authored
9 years ago
by
Danila Klimenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chromatic_tree: updated documentation, fixed test cases for MSVC
parent
2f75565c
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
355 additions
and
77 deletions
+355
-77
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
+139
-3
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
+208
-72
containers_cpp/test/tree_test-inl.h
+8
-2
No files found.
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
View file @
acb6cf6b
...
...
@@ -90,6 +90,132 @@ ChromaticTreeNode<Key, Value>::GetRight() {
return
right_
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeNode
<
Key
,
Value
>::
Retire
()
{
retired_
=
true
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeNode
<
Key
,
Value
>::
IsRetired
()
const
{
return
retired_
;
}
template
<
typename
Key
,
typename
Value
>
embb
::
base
::
Mutex
&
ChromaticTreeNode
<
Key
,
Value
>::
GetMutex
()
{
return
mutex_
;
}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
UniqueHazardPointer
()
:
hazard_guard_
(
NULL
),
undefined_guard_
(
NULL
),
active_
(
false
)
{}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
UniqueHazardPointer
(
AtomicGuard
&
hazard_guard
,
GuardedPtr
undefined_guard
)
:
hazard_guard_
(
&
hazard_guard
),
undefined_guard_
(
undefined_guard
),
active_
(
LoadGuardedPointer
()
==
undefined_guard_
)
{}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
~
UniqueHazardPointer
()
{
if
(
IsActive
())
ClearHazard
();
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
ProtectHazard
(
const
AtomicGuard
&
hazard
)
{
assert
(
OwnsHazardGuard
());
// Read the hazard and store it into the guard
StoreGuardedPointer
(
hazard
.
Load
());
// Check whether the guard is valid
SetActive
(
LoadGuardedPointer
()
==
hazard
.
Load
());
// Clear the guard if it is invalid
if
(
!
IsActive
())
ClearHazard
();
return
IsActive
();
}
template
<
typename
GuardedType
>
UniqueHazardPointer
<
GuardedType
>::
operator
GuardedPtr
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
operator
->
()
const
{
assert
(
IsActive
());
return
LoadGuardedPointer
();
}
template
<
typename
GuardedType
>
GuardedType
&
UniqueHazardPointer
<
GuardedType
>::
operator
*
()
const
{
assert
(
IsActive
());
return
*
(
LoadGuardedPointer
());
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
AdoptGuard
(
const
UniqueHazardPointer
<
GuardedType
>&
other
)
{
assert
(
OwnsHazardGuard
());
StoreGuardedPointer
(
other
.
LoadGuardedPointer
());
SetActive
(
other
.
active_
);
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
Swap
(
UniqueHazardPointer
<
GuardedType
>&
other
)
{
std
::
swap
(
hazard_guard_
,
other
.
hazard_guard_
);
std
::
swap
(
undefined_guard_
,
other
.
undefined_guard_
);
std
::
swap
(
active_
,
other
.
active_
);
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
ReleaseHazard
()
{
assert
(
IsActive
());
GuardedPtr
released_hazard
=
LoadGuardedPointer
();
ClearHazard
();
SetActive
(
false
);
return
released_hazard
;
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
IsActive
()
const
{
return
active_
;
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
SetActive
(
bool
active
)
{
active_
=
active
;
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
ClearHazard
()
{
StoreGuardedPointer
(
undefined_guard_
);
}
template
<
typename
GuardedType
>
typename
UniqueHazardPointer
<
GuardedType
>::
GuardedPtr
UniqueHazardPointer
<
GuardedType
>::
LoadGuardedPointer
()
const
{
return
hazard_guard_
->
Load
();
}
template
<
typename
GuardedType
>
void
UniqueHazardPointer
<
GuardedType
>::
StoreGuardedPointer
(
GuardedPtr
ptr
)
{
hazard_guard_
->
Store
(
ptr
);
}
template
<
typename
GuardedType
>
bool
UniqueHazardPointer
<
GuardedType
>::
OwnsHazardGuard
()
const
{
return
hazard_guard_
!=
NULL
;
}
}
// namespace internal
...
...
@@ -314,7 +440,7 @@ TryDelete(const Key& key, Value& old_value) {
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
size_t
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
GetCapacity
()
{
GetCapacity
()
const
{
return
capacity_
;
}
...
...
@@ -326,8 +452,9 @@ GetUndefinedValue() {
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
IsEmpty
()
{
return
IsLeaf
(
entry_
->
GetLeft
());
IsEmpty
()
const
{
NodePtr
entry
=
entry_
;
//Bug: "operator->()" is not const in AtomicPointer<>
return
IsLeaf
(
entry
->
GetLeft
());
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
...
...
@@ -466,6 +593,15 @@ IsBalanced(const NodePtr& node) const {
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
)
{
node
->
Retire
();
node_lock
.
Unlock
();
NodePtr
node_to_delete
=
node
.
ReleaseHazard
();
node_hazard_manager_
.
EnqueuePointerForDeletion
(
node_to_delete
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
NodePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
NodePool
>::
FreeNode
(
NodePtr
node
)
{
#ifdef EMBB_DEBUG
node
->
GetLeft
()
=
reinterpret_cast
<
NodePtr
>
(
INVALID_POINTER
);
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
View file @
acb6cf6b
...
...
@@ -110,90 +110,206 @@ class ChromaticTreeNode {
*/
AtomicChildPointer
&
GetRight
();
void
Retire
()
{
retired_
=
true
;
}
bool
IsRetired
()
const
{
return
retired_
;
}
embb
::
base
::
Mutex
&
GetMutex
()
{
return
mutex_
;
}
/**
* Marks node for deletion from the tree
*/
void
Retire
();
/**
* Checks whether the node is marked for deletion from the tree
*
* \return \c true if node is retired, \c false otherwise
*/
bool
IsRetired
()
const
;
/**
* Accessor for the FGL mutex
*
* \return Reference to this node's mutex
*/
embb
::
base
::
Mutex
&
GetMutex
();
private
:
/**
* Disable copy construction and assignment.
*/
ChromaticTreeNode
(
const
ChromaticTreeNode
&
);
ChromaticTreeNode
&
operator
=
(
const
ChromaticTreeNode
&
);
const
Key
key_
;
/**< Stored key */
const
Value
value_
;
/**< Stored value */
const
int
weight_
;
/**< Weight of the node */
AtomicChildPointer
left_
;
/**< Pointer to left child node */
AtomicChildPointer
right_
;
/**< Pointer to right child node */
embb
::
base
::
Atomic
<
bool
>
retired_
;
embb
::
base
::
Mutex
mutex_
;
const
Key
key_
;
/**< Stored key */
const
Value
value_
;
/**< Stored value */
const
int
weight_
;
/**< Weight of the node */
AtomicChildPointer
left_
;
/**< Pointer to left child node */
AtomicChildPointer
right_
;
/**< Pointer to right child node */
embb
::
base
::
Atomic
<
bool
>
retired_
;
/**< Retired (marked for deletion) flag */
embb
::
base
::
Mutex
mutex_
;
/**< Fine-grained locking tree: per node mutex */
};
/**
* Ownership wrapper for a hazard pointer
*
* Uses an entry of the hazard table to provide protection for a single
* hazardous pointer. While providing standard pointer dereference and member
* access operators, it requires special care for pointer assignment (realized
* via 'ProtectHazard' method).
* On destruction, it clears the wrapped hazard table entry, releasing the
* protected hazardous pointer (if any).
*
* \tparam GuardedType Type of the object to be protected by the hazard pointer
*/
template
<
typename
GuardedType
>
class
UniqueHazard
Guard
{
class
UniqueHazard
Pointer
{
public
:
typedef
embb
::
base
::
Atomic
<
GuardedType
>
AtomicGuard
;
/**
* Typedef for a pointer to the guarded object.
*/
typedef
GuardedType
*
GuardedPtr
;
/**
* Typedef for a atomic pointer to the guarded object.
*/
typedef
embb
::
base
::
Atomic
<
GuardedPtr
>
AtomicGuard
;
UniqueHazardGuard
(
AtomicGuard
&
guard
,
const
GuardedType
&
undefined_guard
)
:
guard_
(
guard
),
undefined_guard_
(
undefined_guard
),
active_
(
guard_
.
Load
()
==
undefined_guard_
)
{}
/**
* Creates an uninitialized, empty wrapper.
*
* An uninitialized wrapper may only be swapped with another wrapper (using
* \c Swap() method) or checked for being active (using 'IsActive()' method,
* which should always return /c false for an uninitialized wrapper).
*/
UniqueHazardPointer
();
~
UniqueHazardGuard
()
{
if
(
active_
)
SetUndefinedGuard
();
}
/**
* Creates a wrapper that uses the given hazard table entry (referred to as
* "guard") to protect hazardous pointers.
*
* \param[IN] hazard_guard Reference to a hazard table entry
* \param[IN] undefined_guard Dummy value used to clear the hazard table entry
*/
explicit
UniqueHazardPointer
(
AtomicGuard
&
hazard_guard
,
GuardedPtr
undefined_guard
=
NULL
);
bool
ProtectHazard
(
const
AtomicGuard
&
hazard
)
{
// Read the hazard and store it into the guard
guard_
=
hazard
.
Load
();
/**
* If initialized and active, clears the hazard table entry.
*/
~
UniqueHazardPointer
();
// Check whether the guard is valid
active_
=
(
guard_
.
Load
()
==
hazard
.
Load
());
/**
* Tries to protect the given hazard using the wrapped hazard pointer (guard).
* If it succeeds, the hazard may be safely dereferenced as long as the guard
* is not destroyed or reset to protect another hazard.
*
* \param hazard The hazard to be protected
* \return \c true if the specified hazard is now protected by the guard,
* \c false if the hazard was modified by a concurrent thread
*/
bool
ProtectHazard
(
const
AtomicGuard
&
hazard
);
// Clear the guard if it is invalid
if
(
!
active_
)
SetUndefinedGuard
();
/**
* Type cast operator.
*
* \return The hazardous pointer protected by this wrapper
*/
operator
GuardedPtr
()
const
;
return
active_
;
}
/**
* Pointer member access operator.
*
* \return The hazardous pointer protected by this wrapper
*/
GuardedPtr
operator
->
()
const
;
bool
IsActive
()
const
{
return
active_
;
}
/**
* Pointer dereference operator.
*
* \return Reference to the object pointed to by the protected pointer
*/
GuardedType
&
operator
*
()
const
;
operator
GuardedType
()
const
{
assert
(
active_
==
true
);
return
guard_
.
Load
();
}
/**
* Protects the hazard that is currently protected by another wrapper (so it
* becomes protected by two guards simultaneously). The other wrapper remains
* unmodified.
*
* \param other Another wrapper those protected pointer is to be protected by
* the calling wrapper
*/
void
AdoptGuard
(
const
UniqueHazardPointer
<
GuardedType
>&
other
);
GuardedType
operator
->
()
const
{
assert
(
active_
==
true
);
return
guard_
.
Load
();
}
/**
* Swaps the guard ownership with another wrapper. Swaps not just the
* protected hazards, but the hazard guards themselves.
*
* \param other Another wrapper to swap guards with
*/
void
Swap
(
UniqueHazardPointer
<
GuardedType
>&
other
);
void
AdoptGuard
(
const
UniqueHazardGuard
<
GuardedType
>&
other
)
{
guard_
=
other
.
guard_
.
Load
();
active_
=
other
.
active_
;
}
/**
* Clears the hazard guard and returns the hazard previously protected by that
* guard.
*
* \return The hazardous pointer previously protected by this wrapper
*/
GuardedPtr
ReleaseHazard
();
GuardedType
ReleaseHazard
()
{
assert
(
active_
==
true
);
GuardedType
released_hazard
=
guard_
.
Load
();
SetUndefinedGuard
();
active_
=
false
;
return
released_hazard
;
}
/**
* Check whether the wrapper is active.
*
* \return \c true if the wrapper is initialized and currently protecting some
* hazard, \c false otherwise
*/
bool
IsActive
()
const
;
private
:
void
SetUndefinedGuard
()
{
guard_
=
undefined_guard_
;
}
/**
* Sets the 'active' flag of this wrapper.
*
* \param active The new value for the flag
*/
void
SetActive
(
bool
active
);
/**
* Reset the wrapped hazard guard to a state when it is not protecting any
* hazards.
*/
void
ClearHazard
();
// Non-copyable
UniqueHazardGuard
(
const
UniqueHazardGuard
<
GuardedType
>&
);
UniqueHazardGuard
<
GuardedType
>&
operator
=
(
const
UniqueHazardGuard
<
GuardedType
>&
);
/**
* Retrieves the hazardous pointer currently protected by the wrapped guard.
*
* \return The hazardous pointer protected by this wrapper
*/
GuardedPtr
LoadGuardedPointer
()
const
;
/**
* Updates the wrapped guard to protect the specified hazardous pointer.
*
* \param ptr Hazardous pointer to be protected
*/
void
StoreGuardedPointer
(
GuardedPtr
ptr
);
/**
* Check whether the wrapper is initialized (i.e. it wraps some hazard guard)
*
* \return \c true if this wrapper is initialized, \c false otherwise
*/
bool
OwnsHazardGuard
()
const
;
AtomicGuard
&
guard_
;
GuardedType
undefined_guard_
;
/**
* Disable copy construction and assignment.
*/
UniqueHazardPointer
(
const
UniqueHazardPointer
&
);
UniqueHazardPointer
&
operator
=
(
const
UniqueHazardPointer
&
);
/**
* Pointer to a hazard table entry (the guard) that is used to store the
* hazardous pointers
*/
AtomicGuard
*
hazard_guard_
;
/** Dummy value used to clear the hazard guard from any hazards */
GuardedPtr
undefined_guard_
;
/** Flag set to true when the guard is protecting some hazardous pointer */
bool
active_
;
};
...
...
@@ -318,7 +434,7 @@ class ChromaticTree {
* \param[IN] key Key to be removed
*
* \return \c true if the given key-value pair was successfully deleted from
* the tree, \c false if the
tree is out of
memory
* the tree, \c false if the
re is not enough
memory
*/
bool
TryDelete
(
const
Key
&
key
);
...
...
@@ -332,7 +448,7 @@ class ChromaticTree {
* tree for the given key
*
* \return \c true if the given key-value pair was successfully deleted from
* the tree, \c false if the
tree is out of
memory
* the tree, \c false if the
re is not enough
memory
*/
bool
TryDelete
(
const
Key
&
key
,
Value
&
old_value
);
...
...
@@ -342,7 +458,7 @@ class ChromaticTree {
*
* \return Number of key-value pairs the tree can store
*/
size_t
GetCapacity
()
;
size_t
GetCapacity
()
const
;
/**
* Accessor for the dummy value used by the tree
...
...
@@ -356,7 +472,7 @@ class ChromaticTree {
*
* \return \c true if the tree stores no key-value pairs, \c false otherwise
*/
bool
IsEmpty
()
;
bool
IsEmpty
()
const
;
private
:
/**
...
...
@@ -371,8 +487,13 @@ class ChromaticTree {
* Typedef for an atomic pointer to a node of the tree.
*/
typedef
embb
::
base
::
Atomic
<
NodePtr
>
AtomicNodePtr
;
typedef
internal
::
UniqueHazardGuard
<
NodePtr
>
HazardNodePtr
;
/**
* Typedef for an pointer to a node protected by a Hazard Pointer.
*/
typedef
internal
::
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
/**
* Typedef for the UniqueLock class.
*/
typedef
embb
::
base
::
UniqueLock
<
embb
::
base
::
Mutex
>
UniqueLock
;
...
...
@@ -474,15 +595,30 @@ class ChromaticTree {
*/
int
GetHeight
(
const
NodePtr
&
node
)
const
;
/**
* Check whether the tree is currently in a balanced state (if it is a valid
* red-black tree).
*
* \return \c true if the tree is balanced, \c false otherwise
*/
bool
IsBalanced
()
const
;
/**
* Check whether a subtree rooted at the given node is balanced.
*
* \param[IN] node Root of the subtree for which the balance is checked
*
* \return \c true if the tree is balanced, \c false otherwise
*/
bool
IsBalanced
(
const
NodePtr
&
node
)
const
;
void
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
)
{
node
->
Retire
();
node_lock
.
Unlock
();
NodePtr
node_to_delete
=
node
.
ReleaseHazard
();
node_hazard_manager_
.
EnqueuePointerForDeletion
(
node_to_delete
);
}
/**
* Free a tree node using the Hazard Pointers memory reclamation routines.
*
* \param[IN] node A node to be freed.
* \param[IN] node_lock A lock holding the mutex of the \c node to be freed.
*/
void
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
);
/**
* Free a tree node by returning it to the node pool.
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/test/tree_test-inl.h
View file @
acb6cf6b
...
...
@@ -127,7 +127,8 @@ void TreeTest<Tree>::Worker::
ReplaceHalf
()
{
// Replace some of the elements that were inserted earlier
::
std
::
random_shuffle
(
elements_
.
begin
(),
elements_
.
end
());
ElementIterator
elements_middle
=
elements_
.
begin
()
+
elements_
.
size
()
/
2
;
ElementIterator
elements_middle
=
elements_
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
elements_
.
size
()
/
2
);
for
(
ElementIterator
it
=
elements_
.
begin
();
it
!=
elements_middle
;
++
it
)
{
Value
old_value
;
Value
expected
=
it
->
second
;
...
...
@@ -166,7 +167,8 @@ void TreeTest<Tree>::Worker::
DeleteHalf
()
{
// Delete half of the elements from the tree
::
std
::
random_shuffle
(
elements_
.
begin
(),
elements_
.
end
());
ElementIterator
elements_middle
=
elements_
.
begin
()
+
elements_
.
size
()
/
2
;
ElementIterator
elements_middle
=
elements_
.
begin
()
+
static_cast
<
ptrdiff_t
>
(
elements_
.
size
()
/
2
);
for
(
ElementIterator
it
=
elements_
.
begin
();
it
!=
elements_middle
;
++
it
)
{
Value
old_value
;
Value
expected
=
it
->
second
;
...
...
@@ -179,6 +181,7 @@ DeleteHalf() {
template
<
typename
Tree
>
void
TreeTest
<
Tree
>::
TreeTestInsertDelete_Pre
()
{
embb_internal_thread_index_reset
();
tree_
=
new
Tree
(
TREE_CAPACITY
,
bad_key_
,
bad_value_
);
}
...
...
@@ -220,6 +223,7 @@ TreeTestInsertDelete_Post() {
template
<
typename
Tree
>
void
TreeTest
<
Tree
>::
TreeTestConcurrentGet_Pre
()
{
embb_internal_thread_index_reset
();
tree_
=
new
Tree
(
TREE_CAPACITY
/
2
,
bad_key_
,
bad_value_
);
ElementVector
elements
;
...
...
@@ -242,6 +246,7 @@ TreeTestConcurrentGet_Pre() {
template
<
typename
Tree
>
void
TreeTest
<
Tree
>::
TreeTestConcurrentGetMinimal_Pre
()
{
embb_internal_thread_index_reset
();
tree_
=
new
Tree
(
NUM_TEST_THREADS
/
2
,
bad_key_
,
bad_value_
);
for
(
int
i
=
0
;
i
<
NUM_TEST_THREADS
/
2
;
++
i
)
{
...
...
@@ -300,6 +305,7 @@ TreeTestConcurrentGet_Post() {
template
<
typename
Tree
>
void
TreeTest
<
Tree
>::
TreeTestBalance_Pre
()
{
embb_internal_thread_index_reset
();
tree_
=
new
Tree
(
TREE_CAPACITY
,
bad_key_
,
bad_value_
);
}
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment