Skip to content
/ seqlock Public

A C++11 SeqLock implementation with reader/writer support, designed for non-blocking reads

License

Notifications You must be signed in to change notification settings

htfy96/seqlock

Repository files navigation

seqlock

A C++11 SeqLock implementation with reader/writer support, designed for non-blocking reads.

GitHub CircleCI

Usage

#include "seqlock.hpp"

struct Foo {
    int v1;
    double v2;
    long v3;
};

// Basic usage:
using namespace seqlock;
SeqLock<Foo> protected_data {2, 3.0};

protected_data.write(foo_1); // thread-safe. No serialization.
Foo data = protected_data.load(); // does not block write, thread-safe

// Advanced usage:
// mainly used for large structs to avoid copy
{
    auto writer = protected_data.get_writer(); // move-only
    // exclusive access
    auto old_value = writer.read_member(&Foo::v);
    writer.write_member(&Foo::v, old_value + 2);
    // writer lock will be automatically released at the exit of scope
}

std::tuple<int, long> v1_and_v3 = protected_data.load_members(&Foo::v1, &Foo::v3);

A seqlock is a writer-first userspace lock. Reader doesn't block writers by retrying read based on version numbers.

Use cases:

  • busy writer(s)
  • a small number of writers
  • starvation between writers can be tolerated
  • non-blocking reads
template <typename T,
          typename ReadConflictPolicy = conflict_policies::Auto,
          typename WriteConflictPolicy = conflict_policies::Auto,
          typename SeqCounterT = std::uint_fast32_t>
class SeqLock;

Precondition: is_trivial<T>

Config:

  • T: protected data, must be TrivialType
  • ReadConflictPolicy: Behavior when load() finds another thread writing the value. Default: conflict_policies::Auto.
  • WriteConflictPolicy: Behavior when store() finds another thread writing the value. Default: conflict_policies::Auto.
  • SeqCounterT: the sequence counter. Set this to a larger type if there are too many writers causing it to wrap around.

Implementation based on: Can Seqlocks Get Along with Programming Language Memory Models?, Hans-J. Boehm HP Labs

conflict_policies:

  • Pause: use x86 instruction pause on conflict
  • Yield: yield to another thread
  • RetryImmediately: no-op
  • Auto: use Pause when possible, Yield otherwise

About

A C++11 SeqLock implementation with reader/writer support, designed for non-blocking reads

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published