Scala blocking queue, making proper wait - multithreading

I have to implement a blocking and synchronized queue in scala.
If I don't miss something, synchronizing is pretty simple, but for my queue to be blocking I could only think of that (which works) :
def pop() : T = {
this.synchronized
{
_read()
if(_out.isEmpty) throw new Empty()
val ret = _out.head
_out = _out.tail
_length -= 1
return ret
}
}
def waitPop() : T =
{
var ret : Option[T] = None
// Possibly wait forever
while(ret.isEmpty)
{
try { ret = Some(pop) }
catch { case e : Empty => Thread.sleep(1000) }
}
ret.get
}
The problem here is Thread.sleep, it could compromise performance, couldn't it ?
Of course, putting a lower value would mean consuming more of the CPU.
Is there a way to wait properly ?
Thanks.

Thanks to Voo, I got what I needed :
def waitPop() : T =
{
this.synchronized
{
while(isEmpty) wait
pop
}
}
While in push, I added notifyAll (still in a synchronized block).
notify was also working, but with notifyAll the result appears less deterministic.
Thanks a lot !

Related

The .join() method block UI thread even when called on a new thread

I was writing a kotin application that needs to retrive data online.
Using the async(Dispatcher.IO) to get the result from the server and
val variable1 = async(Dispatchers.IO) {
delay(10000)
"I am the guy who comes 10 secs later\nDid you miss me?"
}
using variable1.join() to wait for the result like shown below:
#ExperimentalCoroutinesApi
fun btn(view: android.view.View) {
binding.firstText.text = ""
runBlocking {
launch(Dispatchers.IO) {
//runOnUiThread { pop = popUp() }
val variable1 = async(Dispatchers.IO) {
delay(10000)
"I am the guy who comes 10 secs later\nDid you miss me?"
}
variable1.join()
val a = variable1.await()
Log.d(TAG, "btn: ******************************************************* $a")
runOnUiThread {
//binding.firstText.text = a
}
}
}
}
I have an issue getting the result asynchronously, variable1 keeps blocking the UI thread.
To my understanding, .join() waits for the result before executing. But the problem is that it blocks the UI thread even when its not run on the main thread.
How better should I have done this task? Thanks.
Since I see no evidence of any blocking operations, this is all you need:
fun btn(view: android.view.View) {
binding.firstText.text = ""
viewModelScope.launch {
delay(10_000)
val a = "I am the guy who comes 10 secs later\nDid you miss me?"
Log.d(TAG, "btn: $a")
binding.firstText.text = a
}
}
If you do intend to make blocking operations instead of that delay(10_000), then you can add this:
fun btn(view: android.view.View) {
binding.firstText.text = ""
viewModelScope.launch {
val a = withContext(Dispatchers.IO) {
blockingOperation()
"I am the guy who comes 10 secs later\nDid you miss me?"
}
Log.d(TAG, "btn: $a")
binding.firstText.text = a
}
}
Note there's the viewModelScope, this won't work unless you're inside a ViewModel class. You can use GlobalScope instead to try things out, but this is not a production-worthy solution as it leads to memory leaks at runtime whenever you trigger many such actions while the previous ones are in progress (and they will be because there's nothing cancelling them).

Kotlin thread stops application after finishing

I'm trying to get text from my server using URL.readText, but when the thread finishes the application stops running. Here is my thread function.
fun connect() {
val t = Thread(Runnable {
Thread.sleep(1000)
val str = URL("https://server.necrodragon41.repl.co/server/connect").readText(Charset.forName("UTF-8"))
if (str == "connected") {
Thread.sleep(1500)
ConnectingText.text = "Collecting saved data..."
} else {
ConnectingText.text = "Error connecting."
}
})
t.start()
}
The thread actually finishes running before the application stops because behind the popup that says there was an error I can see the collecting saved data.... How can I avoid the application from stopping?
Thanks in advance.
My assumption it is in Android. One option to update UI from a thread is like this.
fun connect() {
val t = Thread(Runnable {
Thread.sleep(1000)
val str = URL("https://server.necrodragon41.repl.co/server/connect").readText(Charset.forName("UTF-8"))
ConnectingText.post {
if (str == "connected") {
ConnectingText.text = "Collecting saved data..."
} else {
ConnectingText.text = "Error connecting."
}
}
})
t.start()
}
But I strongly suggest for you to check Kotlin Coroutines or RxJava.
Also, if you happen to be create an Restful API, I suggest to use Retrofit for API client.

Stop Thread in Kotlin

First of all, I'm new in Kotlin, so please be nice :).
It's also my first time posting on StackOverflow
I want to literally STOP the current thread that I created but nothing works.
I tried quit(), quitSafely(), interrupt() but nothing works.
I created a class (Data.kt), in which I create and initialize a Handler and HandlerThread as follows :
class Dispatch(private val label: String = "main") {
var handler: Handler? = null
var handlerThread: HandlerThread? = null
init {
if (label == "main") {
handlerThread = null
handler = Handler(Looper.getMainLooper())
} else {
handlerThread = HandlerThread(label)
handlerThread!!.start()
handler = Handler(handlerThread!!.looper)
}
}
fun async(runnable: Runnable) = handler!!.post(runnable)
fun async(block: () -> (Unit)) = handler!!.post(block)
fun asyncAfter(milliseconds: Long, function: () -> (Unit)) {
handler!!.postDelayed(function, milliseconds)
}
fun asyncAfter(milliseconds: Long, runnable: Runnable) {
handler!!.postDelayed(runnable, milliseconds)
}
companion object {
val main = Dispatch()
private val global = Dispatch("global")
//fun global() = global
}
}
And now, in my DataManager, I use these to do asynchronous things :
fun getSomething(forceNetwork: Boolean ) {
val queue1 = Dispatch("thread1") // Create a thread called "thread1"
queue1.async {
for (i in 0..2_000_000) {
print("Hello World")
// Do everything i want in the current thread
}
// And on the main thread I call my callback
Dispatch.main.async {
//callback?.invoke(.........)
}
}
}
Now, in my MainActivity, I made 2 buttons :
One for running the function getSomething()
The other one is used for switching to another Controller View :
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
DataManager.getSomething(true)
}
val button2 = findViewById<Button>(R.id.button2)
button2.setOnClickListener {
val intent = Intent(this, Test::class.java) // Switch to my Test Controller
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
startActivity(intent)
finish()
}
Is there a way to stop the thread, because when I switch to my second View, print("Hello World") is still triggered, unfortunately.
Thanks for helping me guys I hope that you understand !
A thread needs to periodically check a (global) flag and when it becomes true then the thread will break out from the loop. Java threads cannot be safely stopped without its consent.
Refer to page 252 here http://www.rjspm.com/PDF/JavaTheCompleteReference.pdf that describes the true story behind the legend.
I think that a truly interruptible thread is only possible through the support of the operating system kernel. The actual true lock is held deep down by the CPU hardware microprocessor.

how to cap kotlin coroutines maximum concurrency

I've got a Sequence (from File.walkTopDown) and I need to run a long-running operation on each of them. I'd like to use Kotlin best practices / coroutines, but I either get no parallelism, or way too much parallelism and hit a "too many open files" IO error.
File("/Users/me/Pictures/").walkTopDown()
.onFail { file, ex -> println("ERROR: $file caused $ex") }
.filter { ... only big images... }
.map { file ->
async { // I *think* I want async and not "launch"...
ImageProcessor.fromFile(file)
}
}
This doesn't seem to run it in parallel, and my multi-core CPU never goes above 1 CPU's worth. Is there a way with coroutines to run "NumberOfCores parallel operations" worth of Deferred jobs?
I looked at Multithreading using Kotlin Coroutines which first creates ALL the jobs then joins them, but that means completing the Sequence/file tree walk completly bfore the heavy processing join step, and that seems... iffy! Splitting it into a collect and a process step means the collection could run way ahead of the processing.
val jobs = ... the Sequence above...
.toSet()
println("Found ${jobs.size}")
jobs.forEach { it.await() }
This isn't specific to your problem, but it does answer the question of, "how to cap kotlin coroutines maximum concurrency".
EDIT: As of kotlinx.coroutines 1.6.0 (https://github.com/Kotlin/kotlinx.coroutines/issues/2919), you can use limitedParallelism, e.g. Dispatchers.IO.limitedParallelism(123).
Old solution: I thought to use newFixedThreadPoolContext at first, but 1) it's deprecated and 2) it would use threads and I don't think that's necessary or desirable (same with Executors.newFixedThreadPool().asCoroutineDispatcher()). This solution might have flaws I'm not aware of by using Semaphore, but it's very simple:
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
/**
* Maps the inputs using [transform] at most [maxConcurrency] at a time until all Jobs are done.
*/
suspend fun <TInput, TOutput> Iterable<TInput>.mapConcurrently(
maxConcurrency: Int,
transform: suspend (TInput) -> TOutput,
) = coroutineScope {
val gate = Semaphore(maxConcurrency)
this#mapConcurrently.map {
async {
gate.withPermit {
transform(it)
}
}
}.awaitAll()
}
Tests (apologies, it uses Spek, hamcrest, and kotlin test):
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineDispatcher
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.greaterThanOrEqualTo
import org.hamcrest.Matchers.lessThanOrEqualTo
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals
#OptIn(ExperimentalCoroutinesApi::class)
object AsyncHelpersKtTest : Spek({
val actionDelay: Long = 1_000 // arbitrary; obvious if non-test dispatcher is used on accident
val testDispatcher = TestCoroutineDispatcher()
afterEachTest {
// Clean up the TestCoroutineDispatcher to make sure no other work is running.
testDispatcher.cleanupTestCoroutines()
}
describe("mapConcurrently") {
it("should run all inputs concurrently if maxConcurrency >= size") {
val concurrentJobCounter = AtomicInteger(0)
val inputs = IntRange(1, 2).toList()
val maxConcurrency = inputs.size
// https://github.com/Kotlin/kotlinx.coroutines/issues/1266 has useful info & examples
runBlocking(testDispatcher) {
print("start runBlocking $coroutineContext\n")
// We have to run this async so that the code afterwards can advance the virtual clock
val job = launch {
testDispatcher.pauseDispatcher {
val result = inputs.mapConcurrently(maxConcurrency) {
print("action $it $coroutineContext\n")
// Sanity check that we never run more in parallel than max
assertThat(concurrentJobCounter.addAndGet(1), lessThanOrEqualTo(maxConcurrency))
// Allow for virtual clock adjustment
delay(actionDelay)
// Sanity check that we never run more in parallel than max
assertThat(concurrentJobCounter.getAndAdd(-1), lessThanOrEqualTo(maxConcurrency))
print("action $it after delay $coroutineContext\n")
it
}
// Order is not guaranteed, thus a Set
assertEquals(inputs.toSet(), result.toSet())
print("end mapConcurrently $coroutineContext\n")
}
}
print("before advanceTime $coroutineContext\n")
// Start the coroutines
testDispatcher.advanceTimeBy(0)
assertEquals(inputs.size, concurrentJobCounter.get(), "All jobs should have been started")
testDispatcher.advanceTimeBy(actionDelay)
print("after advanceTime $coroutineContext\n")
assertEquals(0, concurrentJobCounter.get(), "All jobs should have finished")
job.join()
}
}
it("should run one at a time if maxConcurrency = 1") {
val concurrentJobCounter = AtomicInteger(0)
val inputs = IntRange(1, 2).toList()
val maxConcurrency = 1
runBlocking(testDispatcher) {
val job = launch {
testDispatcher.pauseDispatcher {
inputs.mapConcurrently(maxConcurrency) {
assertThat(concurrentJobCounter.addAndGet(1), lessThanOrEqualTo(maxConcurrency))
delay(actionDelay)
assertThat(concurrentJobCounter.getAndAdd(-1), lessThanOrEqualTo(maxConcurrency))
it
}
}
}
testDispatcher.advanceTimeBy(0)
assertEquals(1, concurrentJobCounter.get(), "Only one job should have started")
val elapsedTime = testDispatcher.advanceUntilIdle()
print("elapsedTime=$elapsedTime")
assertThat(
"Virtual time should be at least as long as if all jobs ran sequentially",
elapsedTime,
greaterThanOrEqualTo(actionDelay * inputs.size)
)
job.join()
}
}
it("should handle cancellation") {
val jobCounter = AtomicInteger(0)
val inputs = IntRange(1, 2).toList()
val maxConcurrency = 1
runBlocking(testDispatcher) {
val job = launch {
testDispatcher.pauseDispatcher {
inputs.mapConcurrently(maxConcurrency) {
jobCounter.addAndGet(1)
delay(actionDelay)
it
}
}
}
testDispatcher.advanceTimeBy(0)
assertEquals(1, jobCounter.get(), "Only one job should have started")
job.cancel()
testDispatcher.advanceUntilIdle()
assertEquals(1, jobCounter.get(), "Only one job should have run")
job.join()
}
}
}
})
Per https://play.kotlinlang.org/hands-on/Introduction%20to%20Coroutines%20and%20Channels/09_Testing, you may also need to adjust compiler args for the tests to run:
compileTestKotlin {
kotlinOptions {
// Needed for runBlocking test coroutine dispatcher?
freeCompilerArgs += "-Xuse-experimental=kotlin.Experimental"
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
}
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.1'
The problem with your first snippet is that it doesn't run at all - remember, Sequence is lazy, and you have to use a terminal operation such as toSet() or forEach(). Additionally, you need to limit the number of threads that can be used for that task via constructing a newFixedThreadPoolContext context and using it in async:
val pictureContext = newFixedThreadPoolContext(nThreads = 10, name = "reading pictures in parallel")
File("/Users/me/Pictures/").walkTopDown()
.onFail { file, ex -> println("ERROR: $file caused $ex") }
.filter { ... only big images... }
.map { file ->
async(pictureContext) {
ImageProcessor.fromFile(file)
}
}
.toList()
.forEach { it.await() }
Edit:
You have to use a terminal operator (toList) befor awaiting the results
I got it working with a Channel. But maybe I'm being redundant with your way?
val pipe = ArrayChannel<Deferred<ImageFile>>(20)
launch {
while (!(pipe.isEmpty && pipe.isClosedForSend)) {
imageFiles.add(pipe.receive().await())
}
println("pipe closed")
}
File("/Users/me/").walkTopDown()
.onFail { file, ex -> println("ERROR: $file caused $ex") }
.forEach { pipe.send(async { ImageFile.fromFile(it) }) }
pipe.close()
This doesn't preserve the order of the projection but otherwise limits the throughput to at most maxDegreeOfParallelism. Expand and extend as you see fit.
suspend fun <TInput, TOutput> (Collection<TInput>).inParallel(
maxDegreeOfParallelism: Int,
action: suspend CoroutineScope.(input: TInput) -> TOutput
): Iterable<TOutput> = coroutineScope {
val list = this#inParallel
if (list.isEmpty())
return#coroutineScope listOf<TOutput>()
val brake = Channel<Unit>(maxDegreeOfParallelism)
val output = Channel<TOutput>()
val counter = AtomicInteger(0)
this.launch {
repeat(maxDegreeOfParallelism) {
brake.send(Unit)
}
for (input in list) {
val task = this.async {
action(input)
}
this.launch {
val result = task.await()
output.send(result)
val completed = counter.incrementAndGet()
if (completed == list.size) {
output.close()
} else brake.send(Unit)
}
brake.receive()
}
}
val results = mutableListOf<TOutput>()
for (item in output) {
results.add(item)
}
return#coroutineScope results
}
Example usage:
val output = listOf(1, 2, 3).inParallel(2) {
it + 1
} // Note that output may not be in same order as list.
Why not use the asFlow() operator and then use flatMapMerge?
someCoroutineScope.launch(Dispatchers.Default) {
File("/Users/me/Pictures/").walkTopDown()
.asFlow()
.filter { ... only big images... }
.flatMapMerge(concurrencyLimit) { file ->
flow {
emit(runInterruptable { ImageProcessor.fromFile(file) })
}
}.catch { ... }
.collect()
}
Then you can limit the simultaneous open files while still processing them concurrently.
To limit the parallelism to some value there is limitedParallelism function starting from the 1.6.0 version of the kotlinx.coroutines library. It can be called on CoroutineDispatcher object. So to limit threads for parallel execution we can write something like:
val parallelismLimit = Runtime.getRuntime().availableProcessors()
val limitedDispatcher = Dispatchers.Default.limitedParallelism(parallelismLimit)
val scope = CoroutineScope(limitedDispatcher) // we can set limitedDispatcher for the whole scope
scope.launch { // or we can set limitedDispatcher for a coroutine launch(limitedDispatcher)
File("/Users/me/Pictures/").walkTopDown()
.onFail { file, ex -> println("ERROR: $file caused $ex") }
.filter { ... only big images... }
.map { file ->
async {
ImageProcessor.fromFile(file)
}
}.toList().awaitAll()
}
ImageProcessor.fromFile(file) will be executed in parallel using parallelismLimit number of threads.
This will cap coroutines to workers. I'd recommend watching https://www.youtube.com/watch?v=3WGM-_MnPQA
package com.example.workers
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.produce
import kotlin.system.measureTimeMillis
class ChannellibgradleApplication
fun main(args: Array<String>) {
var myList = mutableListOf<Int>(3000,1200,1400,3000,1200,1400,3000)
runBlocking {
var myChannel = produce(CoroutineName("MyInts")) {
myList.forEach { send(it) }
}
println("Starting coroutineScope ")
var time = measureTimeMillis {
coroutineScope {
var workers = 2
repeat(workers)
{
launch(CoroutineName("Sleep 1")) { theHardWork(myChannel) }
}
}
}
println("Ending coroutineScope $time ms")
}
}
suspend fun theHardWork(channel : ReceiveChannel<Int>)
{
for(m in channel) {
println("Starting Sleep $m")
delay(m.toLong())
println("Ending Sleep $m")
}
}

Scala synchronized consumer producer

I want to implement something like the producer-consumer problem (with only one information transmitted at a time), but I want the producer to wait for someone to take his message before leaving.
Here is an example that doesn't block the producer but works otherwise.
class Channel[T]
{
private var _msg : Option[T] = None
def put(msg : T) : Unit =
{
this.synchronized
{
waitFor(_msg == None)
_msg = Some(msg)
notifyAll
}
}
def get() : T =
{
this.synchronized
{
waitFor(_msg != None)
val ret = _msg.get
_msg = None
notifyAll
return ret
}
}
private def waitFor(b : => Boolean) =
while(!b) wait
}
How can I changed it so the producers gets blocked (as the consumer is) ?
I tried to add another waitFor at the end of but sometimes my producer doesn't get released.
For instance, if I have put ; get || get ; put, most of the time it works, but sometimes, the first put is not terminated and the left thread never even runs the get method (I print something once the put call is terminated, and in this case, it never gets printed).
This is why you should use a standard class, SynchronousQueue in this case.
If you really want to work through your problematic code, start by giving us a failing test case or a stack trace from when the put is blocking.
You can do this by means of a BlockingQueue descendant whose producer put () method creates a semaphore/event object that is queued up with the passed message and then the producer thread waits on it.
The consumer get() method extracts a message from the queue and signals its semaphore, so allowing its original producer to run on.
This allows a 'synchronous queue' with actual queueing functionality, should that be what you want?
I came up with something that appears to be working.
class Channel[T]
{
class Transfer[A]
{
protected var _msg : Option[A] = None
def msg_=(a : A) = _msg = Some(a)
def msg : A =
{
// Reading the message destroys it
val ret = _msg.get
_msg = None
return ret
}
def isEmpty = _msg == None
def notEmpty = !isEmpty
}
object Transfer {
def apply[A](msg : A) : Transfer[A] =
{
var t = new Transfer[A]()
t.msg = msg
return t
}
}
// Hacky but Transfer has to be invariant
object Idle extends Transfer[T]
protected var offer : Transfer[T] = Idle
protected var request : Transfer[T] = Idle
def put(msg : T) : Unit =
{
this.synchronized
{
// push an offer as soon as possible
waitFor(offer == Idle)
offer = Transfer(msg)
// request the transfer
requestTransfer
// wait for the transfer to go (ie the msg to be absorbed)
waitFor(offer isEmpty)
// delete the completed offer
offer = Idle
notifyAll
}
}
def get() : T =
{
this.synchronized
{
// push a request as soon as possible
waitFor(request == Idle)
request = new Transfer()
// request the transfer
requestTransfer
// wait for the transfer to go (ie the msg to be delivered)
waitFor(request notEmpty)
val ret = request.msg
// delete the completed request
request = Idle
notifyAll
return ret
}
}
protected def requestTransfer()
{
this.synchronized
{
if(offer != Idle && request != Idle)
{
request.msg = offer.msg
notifyAll
}
}
}
protected def waitFor(b : => Boolean) =
while(!b) wait
}
It has the advantage of respecting symmetry between producer and consumer but it is a bit longer than what I had before.
Thanks for your help.
Edit : It is better but still not safeā€¦

Resources