-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
`CopyableMutex` behaves like `std::mutex` and `CopyableAtomic` behaves like `std:atomic`, except that they also have a copy constructor and copy assignment. For `CopyableAtomic` the current value is copied, for `CopyableMutex` the copy constructor copies nothing and the copy assignment does nothing.
- Loading branch information
Showing
4 changed files
with
78 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2024, University of Freiburg, | ||
// Chair of Algorithms and Data Structures. | ||
// Author: | ||
// Johannes Kalmbach ([email protected]) | ||
|
||
#pragma once | ||
|
||
namespace ad_utility { | ||
// A mutex that can be "copied". The semantics are that copying will create a | ||
// new mutex. This is useful when we just want to make a `const` member function | ||
// that modifies a `mutable` member threadsafe. Note that a copy-constructed | ||
// `CopyableMutex` will be unlocked, even if the source was locked, and that | ||
// copy assignment is a noop. | ||
struct CopyableMutex : std::mutex { | ||
using std::mutex::mutex; | ||
CopyableMutex(const CopyableMutex&) {} | ||
CopyableMutex& operator=(const CopyableMutex&) { return *this; } | ||
}; | ||
|
||
// A `std::atomic` that can be "copied". The semantics are, that copying will | ||
// create a new atomic that is initialized with the value being copied. This is | ||
// useful if we want to store an atomic as a class member, but still want the | ||
// class to be copyable. | ||
template <typename T> | ||
class CopyableAtomic : public std::atomic<T> { | ||
using Base = std::atomic<T>; | ||
|
||
public: | ||
using Base::Base; | ||
CopyableAtomic(const CopyableAtomic& rhs) : Base{rhs.load()} {} | ||
CopyableAtomic& operator=(const CopyableAtomic& rhs) { | ||
static_cast<Base&>(*this) = rhs.load(); | ||
return *this; | ||
} | ||
}; | ||
} // namespace ad_utility |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2024, University of Freiburg, | ||
// Chair of Algorithms and Data Structures. | ||
// Author: | ||
// Johannes Kalmbach ([email protected]) | ||
|
||
#include <gmock/gmock.h> | ||
|
||
#include "util/CopyableSynchronization.h" | ||
|
||
using namespace ad_utility; | ||
|
||
// _________________________________________________ | ||
TEST(CopyableSynchronization, CopyableMutex) { | ||
// Not much to test here. | ||
CopyableMutex m1; | ||
m1.lock(); | ||
[[maybe_unused]] CopyableMutex m2{m1}; | ||
// m2 is still unlocked. | ||
EXPECT_TRUE(m2.try_lock()); | ||
m2.unlock(); | ||
m1 = m2; | ||
// m1 is still locked; | ||
EXPECT_FALSE(m1.try_lock()); | ||
m1.unlock(); | ||
} | ||
|
||
// _________________________________________________ | ||
TEST(CopyableSynchronization, CopyableAtomic) { | ||
CopyableAtomic<int> i1 = 42; | ||
CopyableAtomic<int> i2{i1}; | ||
EXPECT_EQ(i2, 42); | ||
++i2; | ||
EXPECT_EQ(i2, 43); | ||
EXPECT_EQ(i1, 42); | ||
i1 = i2; | ||
EXPECT_EQ(i1, 43); | ||
} |