This repository is a git submodule providing C++ utilities for larger projects, including:
- threadsafe::Unlocked<T, policy::P> : template class to construct a T / mutex pair with locking policy P.
- ReadWrite, Primitive, OneThread : Locking policies.
- AccessConst and Access : Obtain read/write access to Primitive or OneThread locked objects.
- ConstReadAccess, ReadAccess and WriteAccess : Obtain access to ReadWrite protected objects.
- AIReadWriteMutex : A mutex class that provides read/write locking.
- UnlockedBase : A base class pointer to an Unlocked object that can be used in the same way.
- Several utilities like is_single_threaded.
The root project should be using cmake cwm4 and libcwd.
For example, to create an object of type Foo that has read/write protection, one could do:
using namespace threadsafe;
using foo_t = Unlocked<Foo, policy::ReadWrite<AIReadWriteMutex>>;
// Create an object Foo, AIReadWriteMutex pair. Foo will be inaccessible.
foo_t foo;
// A function that gets an already read-locked foo passed, created from a const foo_t.
void f(foo_t::crat const& foo_cr) { foo_cr->const_member(); }
// A function that gets a non-const foo_t passed and write locks it to get write access.
void g(foo_t& foo)
{
foo_t::wat foo_w(foo); // Obtain lock.
foo_w->write_access();
f(foo_w); // Being write locked is OK to pass too.
} // Release lock.
// A function that gets a read-locked foo passed but needs write access.
void h(foo_t::rat& foo_r)
{
// The next line might throw, see below. Normally it would just
// block until all other threads released their read-locks.
foo_t::wat foo_w(foo_r); // Convert read to write lock without releasing the lock.
foo_w->write_access();
}
// A function that takes a read-lock most of the time
// but needs to call h() at the end.
void v(foo_t& foo)
{
for(;;) {
try {
foo_t::rat foo_r(foo);
// Stuff here during which we cannot release the read lock.
h(foo_r); // Throws if some other thread is also trying to get a read-->write lock.
} catch(std::exception const&) {
foo.rd2wryield();
continue;
}
break;
}
}
To clone a project example-project that uses threadsafe simply run:
git clone --recursive <URL-to-project>/example-project.git
cd example-project
AUTOGEN_CMAKE_ONLY=1 ./autogen.sh
The --recursive
is optional because ./autogen.sh
will fix
it when you forgot it.
When using GNU autotools you should of course
not set AUTOGEN_CMAKE_ONLY
. Also, you probably want to use --enable-mainainer-mode
as option to the generated configure
script.
In order to use cmake
configure as usual, for example to build with 16 cores a debug build:
mkdir build_debug
cmake -S . -B build_debug -DCMAKE_MESSAGE_LOG_LEVEL=DEBUG -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DEnableDebugGlobal:BOOL=OFF
cmake --build build_debug --config Debug --parallel 16
Or to make a release build:
mkdir build_release
cmake -S . -B build_release -DCMAKE_BUILD_TYPE=Release
cmake --build build_release --config Release --parallel 16
To add this submodule to a project, that project should already be set up to use utils.
Then simply execute the following in a directory of that project
where you want to have the threadsafe
subdirectory (the
root of the project is recommended as that is the only thing
I've tested so far):
git submodule add https://github.com/CarloWood/threadsafe.git
This should clone threadsafe into the subdirectory threadsafe
, or
if you already cloned it there, it should add it.
Checkout threadsafe-testsuite for an example of a project that uses this submodule.