Code Monkey home page Code Monkey logo

lfds's Introduction

lfds

Implementations of simple lock free data structures in golang and c, because sanity and safety are overrated.

Members

Kevin Bi ([email protected]) and Anirban Biswas ([email protected])

Lock free Hash Map

To test the code, from the c/src directory,

$ make
$ ./lf_map_test

This is an implementation of a lock free hash map inspired by the generation number approach of lock free datastructures in the Linux Scalability paper. When adding entires to the hash map, the version number is checked before modifying the hash table bucket to ensure no changes were made while elements in the linked list were being compared. If the list was modified in that duration, the version number would have been updated, and the insert would fail and be restarted.

lf_map_get() checks the version of the bucket it is searching in every time it inspects a node. If the version number has changed from when it first started searching the list, it starts looking from the head of the list again since the list was modified. The guarantees provided by lf_map_get() are weak. It is possible, that after finding the node in the linked list that has the key we are looking for, the value of the key gets updated.

Lock Free Stack and Queue

Setup workspace for go

$ export GOPATH=`pwd`
$ export GOBIN=$GOPATH/bin
$ PATH=$PATH:$GOPATH:$GOBIN
$ export PATH

Run go tests

To test the go code navigate to the go/src/lfstructures directory make sure your $GOPATH variable is set and run the following command:

$ go test

To test run an individual test run the following command:

$ go test -run NameOfTest

These are golang implementations of a Trieber Stack and a One Producer/One Consumer Queue inspired by various online articles. Go was selected because it was a (relatively) high level language that was not verbose and had atomic functions. After implementing the data structures it is evident why Go prefers the use of channels. For these data structures we relied on the previously mentioned atomic functions as well as unsafe.Pointer types which function similarly to C pointers.

  • Both data structures use a common Node struct and Container interface. The Node struct contains two fields a value, Container interface to store data and next, a pointer to another Node. Nodes are intended to be chained together to make a linked list. The Container interface is used to give the Node the ability to store multiple data types (essentially replicating generica in Java since golang does not have generics). The container has a a Get() and Put() method to add to or remove the data it wraps.

  • The Trieber Stack is implemented as a linked list under the hood and makes use of go's atomic.CompareAndSwapPointer, atomic.LoadPointer, and atomic.StorePointer functions to push and pop nodes to the head of the linked list which is a node field called Top. Push() function atomically gets a pointer to the head of the list and remembers this pointer. It allocates a new node and sets the nodes next field to the head. It then uses attempts to use atomic.CompareAndSwapPointer to update the head of the list to the new node. If this action fails it re-attempts with the new head of the list. Pop() works similarly except it attempts to grab the next node of the current head and reset the head of the list to the next node.

  • The One Producer/One Consumer Queue allows two threads to work concurrently on the datastructure, which is also implemented as a linked list under the hood. It has three fields that are nodes, First, Divider, and Last. One thread, the producer, is allowed to add nodes to the Queue via Produce(), the other, the consumer, will remove nodes from the Queue via Consume(). The Divider field ensures that the producer and consumer threads never overstep their boundaries. The correctness of these operations is also guaranteed by use of go's atomic.CompareAndSwapPointer, atomic.LoadPointer, and atomic.StorePointer functions to append nodes to the tail of the linked list, trim the head of the linked list, and increment the divider node. Having more than one producer or consumer will break the model and cause race conditions and other errosr.

Inspiration and References

lfds's People

Contributors

kevinb22 avatar anirban07 avatar

Stargazers

Akshat Shrivastava avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.