SpinLockThreadMutex
This commit is contained in:
parent
e37e39a496
commit
f8cb01799d
@ -13,7 +13,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("multiplatform") version "2.2.20-Beta1"
|
kotlin("multiplatform") version "2.2.20"
|
||||||
`maven-publish`
|
`maven-publish`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +63,13 @@ kotlin {
|
|||||||
}
|
}
|
||||||
val commonTest by getting
|
val commonTest by getting
|
||||||
|
|
||||||
|
this@kotlin.jvm().compilations.getByName("main").defaultSourceSet {
|
||||||
|
dependencies {
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-annotations-jvm:${this@kotlin.coreLibrariesVersion}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val notJvmMain by creating { dependsOn(commonMain) }
|
val notJvmMain by creating { dependsOn(commonMain) }
|
||||||
val notJvmTest by creating { dependsOn(commonTest) }
|
val notJvmTest by creating { dependsOn(commonTest) }
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,9 @@ package ru.landgrafhomyak.multitasking_0
|
|||||||
|
|
||||||
import kotlin.RuntimeException
|
import kotlin.RuntimeException
|
||||||
|
|
||||||
public class WrongCallerThreadException : RuntimeException {
|
public expect class WrongCallerThreadException : RuntimeException {
|
||||||
public constructor() : super()
|
public constructor()
|
||||||
public constructor(message: String?) : super(message)
|
public constructor(message: String?)
|
||||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
public constructor(message: String?, cause: Throwable?)
|
||||||
public constructor(cause: Throwable?) : super(cause)
|
public constructor(cause: Throwable?)
|
||||||
}
|
}
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0.threads.sync;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import kotlin.annotations.jvm.KotlinActual;
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
public class SpinLockThreadMutex implements ThreadMutex {
|
||||||
|
private static final long CLOSED_USAGES_COUNT = -0x8000_0000_0000_0000L;
|
||||||
|
|
||||||
|
private final AtomicLong _usagesCount;
|
||||||
|
private final AtomicReference<Thread> _currentOwner;
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
public SpinLockThreadMutex() {
|
||||||
|
this._usagesCount = new AtomicLong();
|
||||||
|
this._currentOwner = new AtomicReference<>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
if (this._usagesCount.getAndIncrement() < 0) {
|
||||||
|
this._usagesCount.getAndDecrement();
|
||||||
|
throw new IllegalStateException("Mutex was destroyed");
|
||||||
|
}
|
||||||
|
final Thread thisOwner = Thread.currentThread();
|
||||||
|
while (!this._currentOwner.compareAndSet(null, thisOwner))
|
||||||
|
Thread.onSpinWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
if (!this._currentOwner.compareAndSet(Thread.currentThread(), null)) {
|
||||||
|
if (this._usagesCount.get() < 0)
|
||||||
|
throw new IllegalStateException("Mutex was destroyed");
|
||||||
|
throw new WrongThreadException("Thread doesn't hold this mutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._usagesCount.getAndDecrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
final long cachedUsagesCount = this._usagesCount.compareAndExchange(0, CLOSED_USAGES_COUNT);
|
||||||
|
if (cachedUsagesCount < 0)
|
||||||
|
throw new IllegalStateException("Mutex was destroyed");
|
||||||
|
if (cachedUsagesCount > 0)
|
||||||
|
throw new IllegalStateException("There are thread owning or waiting on this mutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
@KotlinActual
|
||||||
|
@Override
|
||||||
|
@NotNull
|
||||||
|
public ThreadCondition newAssociatedCondition() {
|
||||||
|
return this.new ConditionImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ConditionImpl implements ThreadCondition {
|
||||||
|
private static class QueueNode {
|
||||||
|
public QueueNode next;
|
||||||
|
public final AtomicBoolean isWaiting;
|
||||||
|
|
||||||
|
public QueueNode() {
|
||||||
|
this.next = null;
|
||||||
|
this.isWaiting = new AtomicBoolean(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AtomicReference<QueueNode> _next;
|
||||||
|
private final AtomicLong _usagesCount;
|
||||||
|
|
||||||
|
public ConditionImpl() {
|
||||||
|
if (SpinLockThreadMutex.this._usagesCount.getAndIncrement() < 0) {
|
||||||
|
SpinLockThreadMutex.this._usagesCount.getAndDecrement();
|
||||||
|
throw new IllegalStateException("Mutex was destroyed");
|
||||||
|
}
|
||||||
|
this._next = new AtomicReference<>(null);
|
||||||
|
this._usagesCount = new AtomicLong(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _throwDestroyed() {
|
||||||
|
if (SpinLockThreadMutex.this._usagesCount.get() < 0)
|
||||||
|
throw new IllegalStateException("Condition and associated mutex were destroyed");
|
||||||
|
throw new IllegalStateException("Condition was destroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void await() {
|
||||||
|
if (this._usagesCount.getAndIncrement() < 0) {
|
||||||
|
SpinLockThreadMutex.this._usagesCount.getAndDecrement();
|
||||||
|
this._throwDestroyed();
|
||||||
|
}
|
||||||
|
final Thread currentThread = Thread.currentThread();
|
||||||
|
if (SpinLockThreadMutex.this._currentOwner.get() != currentThread)
|
||||||
|
throw new WrongThreadException("Thread doesn't hold this mutex");
|
||||||
|
|
||||||
|
final QueueNode node = new QueueNode();
|
||||||
|
do {
|
||||||
|
node.next = this._next.get();
|
||||||
|
} while (!this._next.compareAndSet(node.next, node));
|
||||||
|
|
||||||
|
SpinLockThreadMutex.this._currentOwner.set(null);
|
||||||
|
|
||||||
|
while (node.isWaiting.get())
|
||||||
|
Thread.onSpinWait();
|
||||||
|
|
||||||
|
while (!SpinLockThreadMutex.this._currentOwner.compareAndSet(null, currentThread))
|
||||||
|
Thread.onSpinWait();
|
||||||
|
|
||||||
|
this._usagesCount.getAndDecrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean _wakeOne() {
|
||||||
|
while (true) {
|
||||||
|
final QueueNode node = this._next.get();
|
||||||
|
if (node == null) return false;
|
||||||
|
if (!this._next.compareAndSet(node, node.next))
|
||||||
|
continue;
|
||||||
|
node.isWaiting.set(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void wakeOne() {
|
||||||
|
if (this._usagesCount.get() < 0)
|
||||||
|
this._throwDestroyed();
|
||||||
|
|
||||||
|
this._wakeOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
|
@Override
|
||||||
|
public void wakeAll() {
|
||||||
|
if (this._usagesCount.get() < 0)
|
||||||
|
this._throwDestroyed();
|
||||||
|
|
||||||
|
while (this._wakeOne()) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
final long cachedUsagesCount = this._usagesCount.compareAndExchange(0, SpinLockThreadMutex.CLOSED_USAGES_COUNT);
|
||||||
|
if (cachedUsagesCount < 0)
|
||||||
|
throw new IllegalStateException("Condition already was destroyed");
|
||||||
|
if (cachedUsagesCount > 0)
|
||||||
|
throw new IllegalStateException("There are thread waiting on this condition");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0
|
||||||
|
|
||||||
|
public actual typealias WrongCallerThreadException = java.lang.WrongThreadException
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0.threads.sync
|
||||||
|
|
||||||
|
public expect class SpinLockThreadMutex : ThreadMutex {
|
||||||
|
public constructor()
|
||||||
|
|
||||||
|
override fun lock()
|
||||||
|
override fun unlock()
|
||||||
|
override fun newAssociatedCondition(): ThreadCondition
|
||||||
|
override fun destroy()
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0.threads.sync
|
||||||
|
|
||||||
|
public interface ThreadCondition {
|
||||||
|
public fun await()
|
||||||
|
public fun wakeOne()
|
||||||
|
public fun wakeAll()
|
||||||
|
public fun destroy()
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0.threads.sync
|
||||||
|
|
||||||
|
public interface ThreadMutex {
|
||||||
|
public fun lock()
|
||||||
|
public fun unlock()
|
||||||
|
public fun newAssociatedCondition(): ThreadCondition
|
||||||
|
public fun destroy()
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package ru.landgrafhomyak.multitasking_0
|
||||||
|
|
||||||
|
import kotlin.RuntimeException
|
||||||
|
|
||||||
|
public actual class WrongCallerThreadException : RuntimeException {
|
||||||
|
public actual constructor() : super()
|
||||||
|
public actual constructor(message: String?) : super(message)
|
||||||
|
public actual constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
public actual constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user