-
Notifications
You must be signed in to change notification settings - Fork 119
Initial commit without Iterator #257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dxahtepb
wants to merge
2
commits into
cscenter:master
Choose a base branch
from
dxahtepb:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <groupId>dxahtepb</groupId> | ||
| <artifactId>lock-free-set</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
|
|
||
| <properties> | ||
| <maven.compiler.source>1.8</maven.compiler.source> | ||
| <maven.compiler.target>1.8</maven.compiler.target> | ||
| </properties> | ||
|
|
||
| <repositories> | ||
| <repository> | ||
| <id>bintray--maven</id> | ||
| <name>bintray</name> | ||
| <url>https://dl.bintray.com/devexperts/Maven</url> | ||
| </repository> | ||
| </repositories> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>junit</groupId> | ||
| <artifactId>junit</artifactId> | ||
| <version>4.12</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>com.devexperts.lincheck</groupId> | ||
| <artifactId>lincheck</artifactId> | ||
| <version>2.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </project> |
56 changes: 56 additions & 0 deletions
56
...9/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSet.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package ru.cscenter.dxahtepb.lockfreeset; | ||
|
|
||
| /** | ||
| * Lock-Free множество. | ||
| * @param <T> Тип ключей | ||
| */ | ||
| public interface LockFreeSet<T extends Comparable<T>> { | ||
| /** | ||
| * Добавить ключ к множеству | ||
| * | ||
| * Алгоритм должен быть как минимум lock-free | ||
| * | ||
| * @param value значение ключа | ||
| * @return false если value уже существует в множестве, true если элемент был добавлен | ||
| */ | ||
| boolean add(T value); | ||
|
|
||
| /** | ||
| * Удалить ключ из множества | ||
| * | ||
| * Алгоритм должен быть как минимум lock-free | ||
| * | ||
| * @param value значение ключа | ||
| * @return false если ключ не был найден, true если ключ успешно удален | ||
| */ | ||
| boolean remove(T value); | ||
|
|
||
| /** | ||
| * Проверка наличия ключа в множестве | ||
| * | ||
| * Алгоритм должен быть как минимум wait-free | ||
| * | ||
| * @param value значение ключа | ||
| * @return true если элемент содержится в множестве, иначе - false | ||
| */ | ||
| boolean contains(T value); | ||
|
|
||
| /** | ||
| * Проверка множества на пустоту | ||
| * | ||
| * Алгоритм должен быть как минимум wait-free | ||
| * | ||
| * @return true если множество пусто, иначе - false | ||
| */ | ||
| boolean isEmpty(); | ||
|
|
||
| /** | ||
| * Возвращает lock-free итератор для множества | ||
| * | ||
| * Итератор должен базироваться на концепции снапшота, см. | ||
| * @see <a href="http://www.cs.technion.ac.il/~erez/Papers/iterators-disc13.pdf">Lock-Free Data-Structure Iterators</a> | ||
| * | ||
| * @return новый экземпляр итератор для множества | ||
| */ | ||
| java.util.Iterator<T> iterator(); | ||
| } |
125 changes: 125 additions & 0 deletions
125
...LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImpl.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| package ru.cscenter.dxahtepb.lockfreeset; | ||
|
|
||
| import java.util.concurrent.atomic.AtomicMarkableReference; | ||
|
|
||
| public class LockFreeSetImpl<T extends Comparable<T>> implements LockFreeSet<T> { | ||
| private final Node head = new Node(null, null); | ||
|
|
||
| @Override | ||
| public boolean add(final T value) { | ||
| while (true) { | ||
| final Pair pair = find(value); | ||
| final Node prev = pair.prevNode; | ||
| final Node curr = pair.nextNode; | ||
|
|
||
| if (curr == null || curr.value.compareTo(value) != 0) { | ||
| final Node node = new Node(value, curr); | ||
| if (prev.next.compareAndSet(curr, node, false, false)) { | ||
| return true; | ||
| } | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean remove(final T value) { | ||
| while (true) { | ||
| final Pair pair = find(value); | ||
| final Node prev = pair.prevNode; | ||
| final Node curr = pair.nextNode; | ||
|
|
||
| if (curr == null || curr.value.compareTo(value) != 0) { | ||
| return false; | ||
| } else { | ||
| final Node succ = curr.next.getReference(); | ||
| if (!curr.next.compareAndSet(succ, succ, false, true)) { | ||
| continue; | ||
| } | ||
| prev.next.compareAndSet(curr, succ, false, false); | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public boolean contains(final T value) { | ||
| Node curr = head.next.getReference(); | ||
| while (curr != null && curr.value.compareTo(value) < 0) { | ||
| curr = curr.next.getReference(); | ||
| } | ||
| return curr != null && curr.value.compareTo(value) == 0 && !curr.next.isMarked(); | ||
| } | ||
|
|
||
| private Pair find(final T value) { | ||
| retry: | ||
| while (true) { | ||
| Node prev = head; | ||
| Node curr = prev.next.getReference(); | ||
|
|
||
| while (true) { | ||
| if (curr == null) { | ||
| return new Pair(prev, null); | ||
| } | ||
|
|
||
| final Node succ = curr.next.getReference(); | ||
|
|
||
| if (curr.next.isMarked() && !prev.next.compareAndSet(curr, succ, false, false)) { | ||
| continue retry; | ||
| } else { | ||
| if (!curr.next.isMarked() && value.compareTo(curr.value) <= 0) { | ||
| return new Pair(prev, curr); | ||
| } | ||
| prev = curr; | ||
| curr = succ; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isEmpty() { | ||
| return head.next.getReference() == null; | ||
| } | ||
|
|
||
| @Override | ||
| public java.util.Iterator<T> iterator() { | ||
| return null; | ||
| } | ||
|
|
||
| private class Node { | ||
| final T value; | ||
| final AtomicMarkableReference<Node> next; | ||
|
|
||
| Node(final T value, final Node next) { | ||
| this.value = value; | ||
| this.next = new AtomicMarkableReference<>(next, false); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Node(" + (value != null ? value.toString() : "null") + ")"; | ||
| } | ||
| } | ||
|
|
||
| private class Pair { | ||
| final Node prevNode; | ||
| final Node nextNode; | ||
|
|
||
| Pair(final Node prevNode, final Node nextNode) { | ||
| this.prevNode = prevNode; | ||
| this.nextNode = nextNode; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "Pair(" | ||
| + (prevNode != null ? prevNode.toString() : "null") | ||
| + ", " | ||
| + (nextNode != null ? nextNode.toString() : "null") | ||
| + ")"; | ||
| } | ||
| } | ||
| } | ||
45 changes: 45 additions & 0 deletions
45
...et/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplLincheck.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package ru.cscenter.dxahtepb.lockfreeset; | ||
|
|
||
| import com.devexperts.dxlab.lincheck.LinChecker; | ||
| import com.devexperts.dxlab.lincheck.annotations.Operation; | ||
| import com.devexperts.dxlab.lincheck.annotations.Param; | ||
| import com.devexperts.dxlab.lincheck.strategy.stress.StressCTest; | ||
| import com.devexperts.dxlab.lincheck.strategy.stress.StressOptions; | ||
| import com.devexperts.dxlab.lincheck.verifier.linearizability.LinearizabilityVerifier; | ||
| import org.junit.Test; | ||
|
|
||
| @StressCTest(threads = 12) | ||
| public class LockFreeSetImplLincheck { | ||
|
|
||
| private LockFreeSetImpl<Integer> lockFreeSet = new LockFreeSetImpl<>(); | ||
|
|
||
| @Operation | ||
| public boolean add(@Param(name = "x") Integer x) { | ||
| return lockFreeSet.add(x); | ||
| } | ||
|
|
||
| @Operation | ||
| public boolean remove(@Param(name = "x") Integer x) { | ||
| return lockFreeSet.remove(x); | ||
| } | ||
|
|
||
| @Operation | ||
| public boolean contains(@Param(name = "x") Integer x) { | ||
| return lockFreeSet.contains(x); | ||
| } | ||
|
|
||
| @Operation | ||
| public boolean isEmpty(@Param(name = "x") Integer x) { | ||
| return lockFreeSet.contains(x); | ||
| } | ||
|
|
||
| @Test | ||
| public void runTest() { | ||
| LinChecker.check(LockFreeSetImpl.class, new StressOptions() | ||
| .iterations(20000) | ||
| .threads(12) | ||
| .actorsPerThread(100) | ||
| .invocationsPerIteration(200) | ||
| .verifier(LinearizabilityVerifier.class)); | ||
| } | ||
| } |
46 changes: 46 additions & 0 deletions
46
...reeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package ru.cscenter.dxahtepb.lockfreeset; | ||
|
|
||
| import org.junit.Test; | ||
|
|
||
| import static org.junit.Assert.assertFalse; | ||
| import static org.junit.Assert.assertTrue; | ||
|
|
||
| public class LockFreeSetImplTest { | ||
|
|
||
| @Test | ||
| public void testEmptyByDefault() { | ||
| LockFreeSetImpl<Integer> set = new LockFreeSetImpl<>(); | ||
| assertTrue(set.isEmpty()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testBasicOperations() { | ||
| LockFreeSetImpl<Integer> set = new LockFreeSetImpl<>(); | ||
|
|
||
| assertFalse(set.contains(1)); | ||
|
|
||
| assertTrue(set.add(1)); | ||
| assertTrue(set.add(2)); | ||
| assertTrue(set.add(4)); | ||
| assertTrue(set.add(3)); | ||
| assertFalse(set.add(1)); | ||
| assertFalse(set.add(3)); | ||
|
|
||
| assertTrue(set.contains(1)); | ||
| assertTrue(set.contains(2)); | ||
| assertTrue(set.contains(3)); | ||
| assertTrue(set.contains(4)); | ||
|
|
||
| assertTrue(set.remove(1)); | ||
| assertFalse(set.contains(1)); | ||
|
|
||
| assertFalse(set.remove(20)); | ||
|
|
||
| assertFalse(set.isEmpty()); | ||
|
|
||
| assertTrue(set.remove(2)); | ||
| assertTrue(set.remove(3)); | ||
| assertTrue(set.remove(4)); | ||
| assertTrue(set.isEmpty()); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
подумайте, насколько правильно получать так reference и marked. В других случаях тоже