{"id":19937081,"url":"https://github.com/farhadi/spinlock","last_synced_at":"2025-05-03T14:31:03.715Z","repository":{"id":216660369,"uuid":"676528872","full_name":"farhadi/spinlock","owner":"farhadi","description":"Spinlock for Erlang and Elixir","archived":false,"fork":false,"pushed_at":"2024-11-19T14:47:11.000Z","size":15,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-03T00:38:17.740Z","etag":null,"topics":["atomics","elixir","erlang","spinlock"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/farhadi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-08-09T12:07:52.000Z","updated_at":"2024-12-10T08:42:16.000Z","dependencies_parsed_at":"2024-01-28T16:37:49.883Z","dependency_job_id":null,"html_url":"https://github.com/farhadi/spinlock","commit_stats":null,"previous_names":["farhadi/spinlock"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farhadi%2Fspinlock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farhadi%2Fspinlock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farhadi%2Fspinlock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farhadi%2Fspinlock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/farhadi","download_url":"https://codeload.github.com/farhadi/spinlock/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252203182,"owners_count":21710902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atomics","elixir","erlang","spinlock"],"created_at":"2024-11-12T23:30:48.218Z","updated_at":"2025-05-03T14:31:02.563Z","avatar_url":"https://github.com/farhadi.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spinlock\n\n[![CI build status](https://github.com/farhadi/spinlock/workflows/CI/badge.svg)](https://github.com/farhadi/spinlock/actions?query=workflow%3ACI)\n[![codecov](https://codecov.io/gh/farhadi/spinlock/branch/main/graph/badge.svg)](https://codecov.io/gh/farhadi/spinlock)\n[![Hex docs](http://img.shields.io/badge/hex.pm-docs-green.svg?style=flat)](https://hexdocs.pm/spinlock)\n[![Hex Version](http://img.shields.io/hexpm/v/spinlock.svg?style=flat)](https://hex.pm/packages/spinlock)\n[![License](http://img.shields.io/hexpm/l/spinlock.svg?style=flat)](https://github.com/farhadi/spinlock/blob/master/LICENSE)\n\nSpinlock implemented using [atomics](https://erlang.org/doc/man/atomics.html) for Erlang and Elixir.\n\n## Introduction\n\nIn software engineering, locks and mutexes are usually used to prevent race conditions and\ndata corruption that can occur when multiple threads try to access shared data concurrently.\nHowever, in Erlang, we rarely need such locking mechanisms. This is due to the fact that\nconcurrency in Erlang is based on actor model, and each process has its own separate heap\nand does not share memory with other processes. This model inherently avoids many of the\nconcurrency issues associated with shared memory and locking mechanisms.\n\nIn erlang shared resources are typically managed through serialization of access requests\nusing a single gen_server process to handle all requests for a resource. It's also possible\nto replicate mutex behavior using a gen_server process (see [sleeplocks](https://github.com/whitfin/sleeplocks)\nas an example of a lock implementation using gen_servers). Generally, the performance of\nsuch locks are good enough for most use cases. However, in some critical situations where\nsubmicrosecond latency is a requirement, relying on a gen_server based lock may not be the\nbest choice. In such critical cases Spinlocks are used.\n\nSpinlocks are a low-level synchronization mechanism typically used in systems programming,\nsuch as in operating system kernels or in scenarios where you need very fast, lightweight locks.\nThey are called \"spinlocks\" because they cause a thread attempting to acquire the lock to \"spin\"\nin a loop while repeatedly checking if the lock is available. Using this technique we can\nachieve extremely fast lock acquisitions at the expense of CPU cycles spent in busy-waiting.\n\n## Implementation\n\nThis is a Spinlock implementation using atomics for Erlang and Elixir. It is slightly different\nfrom other typical spinlock implementations where the lock state alternates between locked and\nunlocked via an atomic operation. Here, a lock consists of two atomic integers: one tracks\nthe number of requests to acquire the lock, and the other holds the number of releases.\n\nThis approach offers several advantages over conventional spinlock implementations. Firstly,\nlock acquisition is ordered, meaning locks are acquired in the same sequence they are requested.\nThis feature ensures consistent and predictable latency. Secondly, it tracks the number of\nprocesses concurrently busy-waiting to acquire a lock. By allowing only the next process\nto busy-wait in a tight loop and interrupting spinning for the others with `erlang:yield/0`,\nthis method reduces spinlock starvation and offers other processes more opportunities to run.\n\nIn this implementation, attempting to acquire a lock in a locked state will forcibly release\nthe lock after a configurable number of attempts, under the assumption that the process owning\nthe lock has already terminated.\n\n## Use Cases\n\nUse it with caution due to its busy-waiting nature. If the lock is held for extended periods,\nit could waste CPU cycles, adversely affecting overall system performance.\n\nThe rule of thumb to decide whether to use it or not is: \"Employ it only if the operation\nrequiring the lock is a submicrosecond task, and if there's more than a 99% chance that the\nlock can be acquired without busy-waiting.\"\n\nA typical use case in Erlang is implementing transactions for data structures built on top of\natomic arrays (e.g. [Cuckoo Filter](http://github.com/farhadi/cuckoo_filter)).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarhadi%2Fspinlock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffarhadi%2Fspinlock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarhadi%2Fspinlock/lists"}