diff --git a/csc/2019/2.LockFreeSet/ChausovAG/pom.xml b/csc/2019/2.LockFreeSet/ChausovAG/pom.xml
new file mode 100644
index 000000000..1012416da
--- /dev/null
+++ b/csc/2019/2.LockFreeSet/ChausovAG/pom.xml
@@ -0,0 +1,36 @@
+
+ 4.0.0
+
+ dxahtepb
+ lock-free-set
+ 1.0-SNAPSHOT
+
+
+ 1.8
+ 1.8
+
+
+
+
+ bintray--maven
+ bintray
+ https://dl.bintray.com/devexperts/Maven
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.devexperts.lincheck
+ lincheck
+ 2.0
+ test
+
+
+
\ No newline at end of file
diff --git a/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSet.java b/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSet.java
new file mode 100644
index 000000000..0c19fc8b0
--- /dev/null
+++ b/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSet.java
@@ -0,0 +1,56 @@
+package ru.cscenter.dxahtepb.lockfreeset;
+
+/**
+ * Lock-Free множество.
+ * @param Тип ключей
+ */
+public interface LockFreeSet> {
+ /**
+ * Добавить ключ к множеству
+ *
+ * Алгоритм должен быть как минимум 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 Lock-Free Data-Structure Iterators
+ *
+ * @return новый экземпляр итератор для множества
+ */
+ java.util.Iterator iterator();
+}
\ No newline at end of file
diff --git a/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImpl.java b/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImpl.java
new file mode 100644
index 000000000..611925476
--- /dev/null
+++ b/csc/2019/2.LockFreeSet/ChausovAG/src/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImpl.java
@@ -0,0 +1,129 @@
+package ru.cscenter.dxahtepb.lockfreeset;
+
+import java.util.concurrent.atomic.AtomicMarkableReference;
+
+public class LockFreeSetImpl> implements LockFreeSet {
+ 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) {
+ final boolean[] holder = new boolean[1];
+ Node curr = head.next.get(holder);
+ while (curr != null && curr.value.compareTo(value) < 0) {
+ curr = curr.next.get(holder);
+ }
+ final boolean isCurrMarked = holder[0];
+ return curr != null && curr.value.compareTo(value) == 0 && !isCurrMarked;
+ }
+
+ 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 boolean[] holder = new boolean[1];
+ final Node succ = curr.next.get(holder);
+ final boolean isCurrMarked = holder[0];
+
+ if (isCurrMarked && !prev.next.compareAndSet(curr, succ, false, false)) {
+ continue retry;
+ } else {
+ if (!isCurrMarked && 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 iterator() {
+ return null;
+ }
+
+ private class Node {
+ final T value;
+ final AtomicMarkableReference 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")
+ + ")";
+ }
+ }
+}
diff --git a/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplLincheck.java b/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplLincheck.java
new file mode 100644
index 000000000..53f8a569a
--- /dev/null
+++ b/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplLincheck.java
@@ -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 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));
+ }
+}
diff --git a/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplTest.java b/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplTest.java
new file mode 100644
index 000000000..42e289f6b
--- /dev/null
+++ b/csc/2019/2.LockFreeSet/ChausovAG/test/main/java/ru/cscenter/dxahtepb/lockfreeset/LockFreeSetImplTest.java
@@ -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 set = new LockFreeSetImpl<>();
+ assertTrue(set.isEmpty());
+ }
+
+ @Test
+ public void testBasicOperations() {
+ LockFreeSetImpl 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());
+ }
+}