feat(dobj/LockableDObject): added thread safe implimentation of DObject
In order to build a preformant code code base we may want to make parallized code in which case having a lockable DObject is a useful construct
This commit is contained in:
22
src/dobj/private/LockableDObject.cpp
Normal file
22
src/dobj/private/LockableDObject.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include "LockableDObject.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access the underlying DObject.
|
||||||
|
*/
|
||||||
|
DObject& LockableDObject::get() {
|
||||||
|
return object_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the mutex to ensure thread-safe access.
|
||||||
|
*/
|
||||||
|
void LockableDObject::lock() {
|
||||||
|
mutex_.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the mutex after thread-safe access.
|
||||||
|
*/
|
||||||
|
void LockableDObject::unlock() {
|
||||||
|
mutex_.unlock();
|
||||||
|
}
|
||||||
47
src/dobj/public/LockableDObject.h
Normal file
47
src/dobj/public/LockableDObject.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef LOCKABLE_DOBJECT_H
|
||||||
|
#define LOCKABLE_DOBJECT_H
|
||||||
|
|
||||||
|
#include "DObject.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file LockableDObject.h
|
||||||
|
* @brief A lightweight wrapper for DObject that adds locking capabilities.
|
||||||
|
*
|
||||||
|
* This class allows safe concurrent access to a DObject by providing
|
||||||
|
* locking and unlocking methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class LockableDObject
|
||||||
|
* @brief Wrapper for DObject with thread-safe access.
|
||||||
|
*/
|
||||||
|
class LockableDObject {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Default constructor.
|
||||||
|
*/
|
||||||
|
LockableDObject() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Access the underlying DObject.
|
||||||
|
* @return A reference to the wrapped DObject.
|
||||||
|
*/
|
||||||
|
DObject& get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Locks the mutex to ensure thread-safe access.
|
||||||
|
*/
|
||||||
|
void lock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unlocks the mutex after thread-safe access.
|
||||||
|
*/
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DObject object_; ///< The underlying DObject instance.
|
||||||
|
std::mutex mutex_; ///< Mutex for thread-safe access.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOCKABLE_DOBJECT_H
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
# Define the library
|
# Define the library
|
||||||
dobj_sources = files(
|
dobj_sources = files(
|
||||||
'dobj/private/Metadata.cpp'
|
'dobj/private/Metadata.cpp',
|
||||||
|
'dobj/private/DObject.cpp',
|
||||||
|
'dobj/private/LockableDObject.cpp'
|
||||||
)
|
)
|
||||||
|
|
||||||
dobj_headers = files(
|
dobj_headers = files(
|
||||||
'dobj/public/Metadata.h'
|
'dobj/public/Metadata.h',
|
||||||
|
'dobj/public/DObject.h',
|
||||||
|
'dobj/public/LockableDObject.h'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Define the libdobj library so it can be linked against by other parts of the build system
|
# Define the libdobj library so it can be linked against by other parts of the build system
|
||||||
|
|||||||
89
tests/dobj/LockableDObjectTest.cpp
Normal file
89
tests/dobj/LockableDObjectTest.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "LockableDObject.h"
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file LockableDObjectTest.cpp
|
||||||
|
* @brief Unit tests for the LockableDObject class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test suite for the LockableDObject class.
|
||||||
|
*/
|
||||||
|
class LockableDObjectTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
LockableDObject lockableObject;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
// Initialize the LockableDObject for tests
|
||||||
|
DObject& obj = lockableObject.get();
|
||||||
|
obj.setData(42); // Set initial data
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test Verify the default construction of LockableDObject.
|
||||||
|
*/
|
||||||
|
TEST_F(LockableDObjectTest, DefaultConstruction) {
|
||||||
|
EXPECT_NO_THROW(LockableDObject obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test Verify access to the underlying DObject.
|
||||||
|
*/
|
||||||
|
TEST_F(LockableDObjectTest, AccessDObject) {
|
||||||
|
DObject& obj = lockableObject.get();
|
||||||
|
EXPECT_EQ(std::get<int>(obj.getData()), 42); // Ensure the data is accessible
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test Verify locking and unlocking.
|
||||||
|
*/
|
||||||
|
TEST_F(LockableDObjectTest, LockAndUnlock) {
|
||||||
|
EXPECT_NO_THROW(lockableObject.lock());
|
||||||
|
EXPECT_NO_THROW(lockableObject.unlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test Verify thread safety with multiple threads.
|
||||||
|
*/
|
||||||
|
TEST_F(LockableDObjectTest, ThreadSafety) {
|
||||||
|
const int numThreads = 10;
|
||||||
|
std::vector<std::thread> threads;
|
||||||
|
std::atomic<int> successCount{0};
|
||||||
|
|
||||||
|
// Each thread tries to update the data
|
||||||
|
for (int i = 0; i < numThreads; ++i) {
|
||||||
|
threads.emplace_back([this, i, &successCount]() {
|
||||||
|
lockableObject.lock();
|
||||||
|
DObject& obj = lockableObject.get();
|
||||||
|
obj.setData(i);
|
||||||
|
if (std::get<int>(obj.getData()) == i) {
|
||||||
|
successCount++;
|
||||||
|
}
|
||||||
|
lockableObject.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& t : threads) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_EQ(successCount, numThreads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test Verify that the DObject remains consistent when accessed via LockableDObject.
|
||||||
|
*/
|
||||||
|
TEST_F(LockableDObjectTest, ConsistentState) {
|
||||||
|
lockableObject.lock();
|
||||||
|
DObject& obj = lockableObject.get();
|
||||||
|
obj.setData(100);
|
||||||
|
EXPECT_EQ(std::get<int>(obj.getData()), 100);
|
||||||
|
lockableObject.unlock();
|
||||||
|
|
||||||
|
lockableObject.lock();
|
||||||
|
EXPECT_EQ(std::get<int>(lockableObject.get().getData()), 100);
|
||||||
|
lockableObject.unlock();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user