SpinLockThreadMutex
This commit is contained in:
parent
e37e39a496
commit
f8cb01799d
@ -13,7 +13,7 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform") version "2.2.20-Beta1"
|
||||
kotlin("multiplatform") version "2.2.20"
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
@ -63,6 +63,13 @@ kotlin {
|
||||
}
|
||||
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 notJvmTest by creating { dependsOn(commonTest) }
|
||||
|
||||
|
||||
@ -2,9 +2,9 @@ package ru.landgrafhomyak.multitasking_0
|
||||
|
||||
import kotlin.RuntimeException
|
||||
|
||||
public class WrongCallerThreadException : RuntimeException {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
public expect class WrongCallerThreadException : RuntimeException {
|
||||
public constructor()
|
||||
public constructor(message: String?)
|
||||
public constructor(message: String?, cause: Throwable?)
|
||||
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