Skip to content

Commit

Permalink
+add atomic examples to read_write_test.
Browse files Browse the repository at this point in the history
  • Loading branch information
ermig1979 committed Nov 1, 2022
1 parent 3bd6ea6 commit 95d01a6
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 141 deletions.
Original file line number Diff line number Diff line change
@@ -1,124 +1,14 @@
#include "Test.h"

#include <shared_mutex>
#include <mutex>
#include <atomic>
#include "TestStub.h"
#include "TestMutex.h"
#include "TestAtomic.h"

namespace Test
{
class StubTest : public BaseTest
{
public:
StubTest(const Options& options)
: BaseTest("stub", options)
{
Run();
}

protected:
virtual void Read(Data& data)
{
};

virtual void Write(const Data& data)
{
};
};

//---------------------------------------------------------------------------------------------

class ErrorTest : public BaseTest
{
public:
ErrorTest(const Options& options)
: BaseTest("error", options)
, _data(options.size)
{
Run();
}

protected:
virtual void Read(Data& data)
{
data.Assign(_data);
};

virtual void Write(const Data& data)
{
_data.Assign(data);
};

private:
Data _data;
};

//---------------------------------------------------------------------------------------------

class StdMutexTest : public BaseTest
{
public:
StdMutexTest(const Options& options)
: BaseTest("std::mutex", options)
, _data(options.size)
{
Run();
}

protected:
virtual void Read(Data& data)
{
std::lock_guard<std::mutex> lock(_mutex);
data.Assign(_data);
};

virtual void Write(const Data& data)
{
std::lock_guard<std::mutex> lock(_mutex);
_data.Assign(data);
};

private:
Data _data;
std::mutex _mutex;
};

//---------------------------------------------------------------------------------------------

class StdSharedMutexTest : public BaseTest
{
public:
StdSharedMutexTest(const Options& options)
: BaseTest("std::shared_mutex", options)
, _data(options.size)
{
Run();
}

protected:
virtual void Read(Data& data)
{
std::shared_lock<std::shared_mutex> lock(_mutex);
data.Assign(_data);
};

virtual void Write(const Data& data)
{
std::unique_lock<std::shared_mutex> lock(_mutex);
_data.Assign(data);
};

private:
Data _data;
std::shared_mutex _mutex;
};

//---------------------------------------------------------------------------------------------

class CondVarAndAtomicTest : public BaseTest
class CondVarAndAtomicTest : public TestBase
{
public:
CondVarAndAtomicTest(const Options& options)
: BaseTest("std::conditional_variable + std::atomic", options)
: TestBase("std::conditional_variable + std::atomic", options)
, _data(options.size)
, _writers(0)
, _readers(0)
Expand Down Expand Up @@ -164,11 +54,11 @@ namespace Test

//---------------------------------------------------------------------------------------------

class MultipleBufferTest : public BaseTest
class MultipleBufferTest : public TestBase
{
public:
MultipleBufferTest(const Options& options)
: BaseTest("multiple buffer", options)
: TestBase("multiple buffer", options)
{
const size_t SIZE = 4;
_buffers.reserve(SIZE);
Expand Down Expand Up @@ -261,21 +151,51 @@ namespace Test

//-------------------------------------------------------------------------------------------------

int main(int argc, char* argv[])
namespace Test
{
Test::Options options(256, 16, 10.0);
void TestWithErrors()
{
Options options(256, 16, 1.0);

TestStub stub(options);

//Test::StubTest stub(options);
TestNoSync noSync(options);
}

//Test::ErrorTest error(options);
void TestValidated()
{
Options options(256, 16, 3.0);

//Test::StdMutexTest stdMutex(options);
TestMutex stdMutex(options);

//Test::StdSharedMutexTest stdSharedMutex(options);
TestSharedMutex stdSharedMutex(options);

TestAtomicV1 atomicV1(options);

TestAtomicV2 atomicV2(options);

TestAtomicV3 atomicV3(options);
}

void TestExperiments()
{
Options options(256, 16, 3.0);

//TestAtomicV1 atomicV1(options);

TestAtomicV3 atomicV3(options);
}
}

//-------------------------------------------------------------------------------------------------

int main(int argc, char* argv[])
{
//Test::TestWithErrors();

//Test::CondVarAndAtomicTest condVarAndAtomic(options);
Test::TestValidated();

Test::MultipleBufferTest multipleBuffer(options);
//Test::TestExperiments();

return 0;
}
141 changes: 141 additions & 0 deletions thread_tests/read_write_test/TestAtomic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#pragma once

#include <atomic>

#include "TestBase.h"

namespace Test
{
class TestAtomicV1 : public TestBase
{
public:
TestAtomicV1(const Options& options)
: TestBase("atomic: simple spin lock", options)
, _data(options.size)
, _sync(0)
{
Run();
}

protected:
virtual void Read(Data& data)
{
while (true)
{
bool expected = 0;
if (_sync.compare_exchange_weak(expected, 1, std::memory_order_acquire))
break;
}
data.Assign(_data);
_sync.store(0, std::memory_order_release);
};

virtual void Write(const Data& data)
{
while (true)
{
bool expected = 0;
if (_sync.compare_exchange_weak(expected, 1, std::memory_order_acquire))
break;
}
_data.Assign(data);
_sync.store(0, std::memory_order_release);
};

private:
Data _data;
std::atomic<bool> _sync;
};

//---------------------------------------------------------------------------------------------

class TestAtomicV2 : public TestBase
{
public:
TestAtomicV2(const Options& options)
: TestBase("atomic: spin lock + read/write counters", options)
, _data(options.size)
, _sync(0)
, _writers(0)
, _readers(0)
{
Run();
}

protected:
virtual void Read(Data& data)
{
while (true)
{
bool expected = 0;
if (_sync.compare_exchange_weak(expected, 1, std::memory_order_acquire))
break;
}
while (_writers.load());
_readers++;
_sync.store(0, std::memory_order_release);
data.Assign(_data);
_readers--;
};

virtual void Write(const Data& data)
{
while (true)
{
bool expected = 0;
if (_sync.compare_exchange_weak(expected, 1, std::memory_order_acquire))
break;
}
_writers.store(1);
while (_readers.load());
_sync.store(0, std::memory_order_release);
_data.Assign(data);
_writers.store(0);
};

private:
Data _data;
std::atomic<bool> _sync;
std::atomic<int> _readers, _writers;
};

//---------------------------------------------------------------------------------------------

class TestAtomicV3 : public TestBase
{
static const int WRITE_BIT = 0x00010000;
public:
TestAtomicV3(const Options& options)
: TestBase("atomic: spin lock + read/write mask", options)
, _data(options.size)
, _sync(0)
{
Run();
}

protected:
virtual void Read(Data& data)
{
while (true)
{
int readers = _sync.load(std::memory_order_acquire) & (~WRITE_BIT);
if (_sync.compare_exchange_weak(readers, readers + 1, std::memory_order_acquire))
break;
}
data.Assign(_data);
_sync.fetch_sub(1, std::memory_order_release);
};

virtual void Write(const Data& data)
{
_sync.fetch_or(WRITE_BIT, std::memory_order_acquire);
while (_sync.load(std::memory_order_acquire) & (~WRITE_BIT));
_data.Assign(data);
_sync.store(0, std::memory_order_release);
};

private:
Data _data;
std::atomic<int> _sync;
};
}
Loading

0 comments on commit 95d01a6

Please sign in to comment.