Skip to content

SiddiqSoft/rwlenvelope

Repository files navigation

RWLEnvelope : A simple read-writer lock envelope

CodeQL Build Status

Objective

  • Avoid re-implementing the rw-lock; standard C++ (since C++14) has a good reader-writer lock implementation.
  • Provide a simple, convenience layer atop the underlying std::unique_lock and std::shared_lock access to some type.

WE DO NOT IMPLEMENT a read-writer lock; the standard C++ library has one.
We provide a header-only package simplifying the locking code around thread-safe access to your underlying type.
NOT a wrapper; an envelope.

Requirements

  • You must be able to use <shared_mutex> and <mutex>.
  • Minimal target is C++17.
  • The build and tests are for Visual Studio 2019 under x64.
  • We use nlohmann::json only in our tests and the library is aware to provide a conversion operator if library is detected.

Usage

  • Use the nuget SiddiqSoft.RWLEnvelope
  • Copy paste..whatever works.
  • The idea is to not "wrap" the underlying type forcing you to either inherit or re-implement the types but to take advantage of the underlying type's interface whilst ensuring that we have the necessary locks.
  • Two methods:
    • Observer/mutator model with callback and custom return to limit access and to focus the where and how to access the underlying type.
    • Take advantage of init-statement in if-statement to get the contained object within a lock and have the compiler auto-release once we leave scope.
  • A sample implementation (say you want a std::map with reader-writer lock)
    • using RWLMap = siddiqsoft::RWLEnvelope<std::map>;
#include "gtest/gtest.h"
#include "nlohmann/json.hpp"
#include "siddiqsoft/RWLEnvelope.hpp"


TEST(examples, AssignWithCallbacks)
{
	siddiqsoft::RWLEnvelope<nlohmann::json> docl; // we will assign later
	nlohmann::json                          doc2 {{"baa", 0x0baa}, {"fee", 0x0fee}, {"bee", 0x0bee}};

	// Move assign here post init
	docl.reassign(std::move(doc2));
	// Must be empty since we moved it into the envelope
	EXPECT_TRUE(doc2.empty());

	// Check we have pre-change value.. Note that here we return a boolean to avoid data copy
	EXPECT_TRUE(docl.observe<bool>([](const auto& doc) -> bool {
		return (doc.value("fee", 0xfa17) == 0x0fee) && (doc.value("baa", 0xfa17) == 0x0baa) && (doc.value("bee", 0xfa17) == 0x0bee);
	}));

	EXPECT_EQ(3, docl.observe<size_t>([](const auto& doc) { return doc.size(); }));
}


TEST(examples, AssignWithDirectLocks)
{
	siddiqsoft::RWLEnvelope<nlohmann::json> docl({{"foo", "bar"}, {"few", "lar"}});
	nlohmann::json                          doc2 {{"baa", 0x0baa}, {"fee", 0x0fee}, {"bee", 0x0bee}};

	// Previous document has two items..
	if (auto const& [doc, rl] = docl.readLock(); rl) { EXPECT_EQ(2, doc.size()); }

	// Modify the item (replace the initial with new)
	if (auto [doc, wl] = docl.writeLock(); wl) { doc = std::move(doc2); };

	//doc2 -> Must be empty since we moved it into the envelope
	EXPECT_TRUE(doc2.empty());

	// Check we have post-change value..
	if (const auto& [doc, rl] = docl.readLock(); rl) { EXPECT_EQ(3, doc.size()); }
}

Additional examples.

© 2021 Siddiq Software LLC. All rights reserved.