Kotlin coroutines in Minecraft spigot plugin - multithreading

In the docs it says that coroutines are lighter than threads and so I wanted to use a kotlin coroutine instead of the BukkitRunnable.
//Defined as class field
private val scope = coroutineScope(Dispatchers.Default)
//In class method
scope.launch {/* wait some seconds and then change blockdata */}
Calling setBlockData from Dispatchers.Default thread throws an error because the spigot API is not thread safe and you can't call API stuff from a thread other than the main.
java.lang.IllegalStateException: Asynchronous block remove!
I was thinking that changing block data is the equivalent of android UI changes in Minecraft which means that the coroutine needs to be run/injected into the main thread. So it would make sense to run my coroutine in Dispatchers.Main. However, I can't find a way use Dispatchers.Main and set it to the main thread without getting an illegalStateException
I hope my logic is correct here

If you want a simple method that is able to bridge the suspending code with the main thread (with the possibility of fetching some information from the main thread and use that on your coroutine), you can use this method:
suspend fun <T> suspendSync(plugin: Plugin, task: () -> T): T = withTimeout(10000L) {
// Context: The current coroutine context
suspendCancellableCoroutine { cont ->
// Context: The current coroutine context
Bukkit.getScheduler().runTask(plugin) {
// Context: Bukkit MAIN thread
// runCatching is used to forward any exception that may occur here back to
// our coroutine, keeping the exception transparency of Kotlin coroutines
runCatching(task).fold({ cont.resume(it) }, cont::resumeWithException)
}
}
}
I've commented on what context each part of the code is executed so you can visualize the context switch. suspendCancellableCoroutine is a way of getting hold of the continuation object all coroutines use under the hood, so we can manually resume it once the main thread execute our task.
The outer block withTimeout is used so that if the main thread does not complete our task within 10 seconds, our coroutine gives up instead of hanging forever.
And the use is very simple too:
val plugin = // comes from somewhere
// example coroutine scope
CoroutineScope(Dispatchers.Default).launch {
// doing stuff async
// oh no, I need some data from the main thread!
val block = suspendSync(plugin) {
// this code runs on the MAIN thread
Bukkit.getWorld("blah").getBlockAt(0, 0, 0)
}
// back to async here, do stuff with block (just don't MODIFY it async, use more suspendSync if needed)
}
If you have any questions or think I can improve this answer, don't be afraid of letting me know.

Related

Kotlin: Why isn't job.invokeOnCompletion() block running on main thread?

In my Android application I have code that should run periodically in its own coroutine and should be cancelable.
for this I have the following functions:
startJob(): Initializes the job, sets up invokeOnCompletion() and starts the work loop in the respective scope
private fun startJob() {
if (::myJob.isInitialized && myJob.isActive) {
return
}
myJob= Job()
myJob.invokeOnCompletion {
it?.message.let {
var msg = it
if (msg.isNullOrBlank()) {
msg = "Job stopped. Reason unknown"
}
myJobCompleted(msg)
}
}
CoroutineScope(Dispatchers.IO + myJob).launch {
workloop()
}
}
workloop(): The main work loop. Do some work in a loop with a set delay in each iteration:
private suspend fun workloop() {
while (true) {
// doing some stuff here
delay(setDelayInMilliseconds)
}
}
myJobCompleted: do some finalizing. For now simply log a message for testing.
private fun myJobCompleted(msg: String) {
try {
mainActivityReference.logToGUI(msg)
}
catch (e:Exception){
println("debug: " + e.message)
}
}
Running this and calling myJob.Cancel() will throw the following exception in myJobCompleted():
debug: Only the original thread that created a view hierarchy can touch its views.
I'm curious as to why this code isn't running on the main thread, since startJob() IS called from the main thread?
Furthermore: is there a option similar to using a CancellationTokenSource in c#, where the job is not immediately cancelled, but a cancellation request can be checked each iteration of the while loop?
Immediately breaking off the job, regardless of what it is doing (although it will pretty much always be waiting for the delay on cancellation) doesn't seem like a good idea to me.
It is not the contract of Job.invokeOnCompletion to run on the same thread where Job is created. Moreover, such a contract would be impossible to implement.
You can't expect an arbitrary piece of code to run on an arbitrary thread, just because there was some earlier method invocation on that thread. The ability of the Android main GUI thread to execute code submitted from the outside is special, and involves the existence a top-level event loop.
In the world of coroutines, what controls thread assignment is the coroutine context, while clearly you are outside of any context when creating the job. So the way to fix it is to explicitly launch(Dispatchers.Main) a coroutine from within invokeOnCompletion.
About you question on cancellation, you can use withContext(NonCancellable) to surround the part of code you want to protect from cancellation.

Without AsyncTask, running a thread in background and updating the UI Thread

I was trying to update the recycler view content from a background thread in Kotlin. I am not using AsyncTask.
Here is my code, i want to know if there is any better way than this:
In my MainActivity, i have progressThread as a member variable.
var progressThread = Thread()
Then in my method where i want to run the thread first i am defining it...like
progressThread = Thread (
Runnable {
kotlin.run {
try {
while (i <= 100 && !progressThread.isInterrupted) {
Thread.sleep(200)
//Some Logic
runOnUiThread {
//this runs in ui thread
}
i++
}
}catch (e:InterruptedException){
progressThread.interrupt()
}
}
})
after that i am starting it in the same method as
progressThread.start()
and for stopping it, i have a listener to cancel the progress and in the callback of that listener, i have written:
progressThread.interrupt()
Updated
Coroutines are stable now,: https://kotlinlang.org/docs/reference/coroutines-overview.html
Old Answer
Yes, you can do this using doAsync from kotlin anko library that is fairly simple and easy to use.
add following line in module level gradle file:
compile "org.jetbrains.anko:anko-commons:0.10.0"
Code example:
val future = doAsync {
// do your background thread task
result = someTask()
uiThread {
// use result here if you want to update ui
updateUI(result)
}
}
code block written in uiThread will only be executed if your Activity or Fragment is in foreground mode (It is lifecycle aware). So if you are trying to stop thread because you don't want your ui code to execute when Activity is in background, then this is an ideal case for you.
As you can check doAsync returns a Future object so you can cancel the background task, by cancel() function:
future.cancel(true)
pass true if you want to stop the thread even when it has started executing.
If you have more specialised case to handle stopping case then you can do the same thing as in your example.
You can use Kotlin Coroutines also but its in Experimental phase, still you can try it out: https://kotlinlang.org/docs/reference/coroutines.html

.wait() on a task in c++/cx throws exception

I have a function which calls Concurrency::create_task to perform some work in the background. Inside that task, there is a need to call a connectAsync method on the StreamSocket class in order to connect a socket to a device. Once the device is connected, I need to grab some references to things inside the connected socket (like input and output streams).
Since it is an asynchronous method and will return an IAsyncAction, I need to create another task on the connectAsync function that I can wait on. This works without waiting, but complications arise when I try to wait() on this inner task in order to error check.
Concurrency::create_task( Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService::FromIdAsync( device_->Id ) )
.then( [ this ]( Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService ^device_service_ )
{
_device_service = device_service_;
_stream_socket = ref new Windows::Networking::Sockets::StreamSocket();
// Connect the socket
auto inner_task = Concurrency::create_task( _stream_socket->ConnectAsync(
_device_service->ConnectionHostName,
_device_service->ConnectionServiceName,
Windows::Networking::Sockets::SocketProtectionLevel::BluetoothEncryptionAllowNullAuthentication ) )
.then( [ this ]()
{
//grab references to streams, other things.
} ).wait(); //throws exception here, but task executes
Basically, I have figured out that the same thread (presumably the UI) that creates the initial task to connect, also executes that task AND the inner task. Whenever I attempt to call .wait() on the inner task from the outer one, I immediately get an exception. However, the inner task will then finish and connect successfully to the device.
Why are my async chains executing on the UI thread? How can i properly wait on these tasks?
In general you should avoid .wait() and just continue the asynchronous chain. If you need to block for some reason, the only fool-proof mechanism would be to explicitly run your code from a background thread (eg, the WinRT thread pool).
You could try using the .then() overload that takes a task_options and pass concurrency::task_options(concurrency::task_continuation_context::use_arbitrary()), but that doesn't guarantee the continuation will run on another thread; it just says that it's OK if it does so -- see documentation here.
You could set an event and have the main thread wait for it. I have done this with some IO async operations. Here is a basic example of using the thread pool, using an event to wait on the work:
TEST_METHOD(ThreadpoolEventTestCppCx)
{
Microsoft::WRL::Wrappers::Event m_logFileCreatedEvent;
m_logFileCreatedEvent.Attach(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
long x = 10000000;
auto workItem = ref new WorkItemHandler(
[&m_logFileCreatedEvent, &x](Windows::Foundation::IAsyncAction^ workItem)
{
while (x--);
SetEvent(m_logFileCreatedEvent.Get());
});
auto asyncAction = ThreadPool::RunAsync(workItem);
WaitForSingleObjectEx(m_logFileCreatedEvent.Get(), INFINITE, FALSE);
long i = x;
}
Here is a similar example except it includes a bit of Windows Runtime async IO:
TEST_METHOD(AsyncOnThreadPoolUsingEvent)
{
std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
int i;
auto workItem = ref new WorkItemHandler(
[_completed, &i](Windows::Foundation::IAsyncAction^ workItem)
{
Windows::Storage::StorageFolder^ _picturesLibrary = Windows::Storage::KnownFolders::PicturesLibrary;
Concurrency::task<Windows::Storage::StorageFile^> _getFileObjectTask(_picturesLibrary->GetFileAsync(L"art.bmp"));
auto _task2 = _getFileObjectTask.then([_completed, &i](Windows::Storage::StorageFile^ file)
{
i = 90210;
_completed->set();
});
});
auto asyncAction = ThreadPool::RunAsync(workItem);
_completed->wait();
int j = i;
}
I tried using an event to wait on Windows Runtime Async work, but it blocked. That's why I had to use the threadpool.

Interrupt parallel Stream execution

Consider this code :
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
tasks are a list of Runnables that should be executed in parallel.
When we start this thread, and it begins its execution, then depending on some calculations we need to interrupt (cancel) all those tasks.
Interrupting the Thread will only stop one of exections. How do we handle others? or maybe Streams should not be used that way? or you know a better solution?
You can use a ForkJoinPool to interrupt the threads:
#Test
public void testInterruptParallelStream() throws Exception {
final AtomicReference<InterruptedException> exc = new AtomicReference<>();
final ForkJoinPool forkJoinPool = new ForkJoinPool(4);
// use the pool with a parallel stream to execute some tasks
forkJoinPool.submit(() -> {
Stream.generate(Object::new).parallel().forEach(obj -> {
synchronized (obj) {
try {
// task that is blocking
obj.wait();
} catch (final InterruptedException e) {
exc.set(e);
}
}
});
});
// wait until the stream got started
Threads.sleep(500);
// now we want to interrupt the task execution
forkJoinPool.shutdownNow();
// wait for the interrupt to occur
Threads.sleep(500);
// check that we really got an interruption in the parallel stream threads
assertTrue(exc.get() instanceof InterruptedException);
}
The worker threads do really get interrupted, terminating a blocking operation. You can also call shutdown() within the Consumer.
Note that those sleeps might not be tweaked for a proper unit test, you might have better ideas to just wait as necessary. But it is enough to show that it is working.
You aren't actually running the Runnables on the Thread you are creating. You are running a thread which will submit to a pool, so:
Thread thread = new Thread(() -> tasks.parallelStream().forEach(Runnable::run));
In this example you are in lesser terms doing
List<Runnable> tasks = ...;
Thread thread = new Thread(new Runnable(){
public void run(){
for(Runnable r : tasks){
ForkJoinPool.commonPool().submit(r);
}
}
});
This is because you are using a parallelStream that delegates to a common pool when handling parallel executions.
As far as I know, you cannot get a handle of the Threads that are executing your tasks with a parallelStream so may be out of luck. You can always do tricky stuff to get the thread but probably isn't the best idea to do so.
Something like the following should work for you:
AtomicBoolean shouldCancel = new AtomicBoolean();
...
tasks.parallelStream().allMatch(task->{
task.run();
return !shouldCancel.get();
});
The documentation for the method allMatch specifically says that it "may not evaluate the predicate on all elements if not necessary for determining the result." So if the predicate doesn't match when you want to cancel, then it doesn't need to evaluate any more. Additionally, you can check the return result to see if the loop was cancelled or not.

F#: purpose of SwitchToThreadPool just before async return

In the MS docs for Async.SwitchToNewThread one of the examples given is:
let asyncMethod f =
async {
do! Async.SwitchToNewThread()
let result = f()
do! Async.SwitchToThreadPool()
return result
}
What is the purpose of switching to the thread pool immediately before a return statement? I understand why you might want to switch from a dedicated thread to the thread pool when the async block has more work to do but that is not the case here.
This is not part of the main question, but I'm also curious to know why SwitchToNewThread and SwitchToThreadPool return an Async. Is there ever a use case where you would not want to immediately "do!" these tasks? Thank you
The example could be clearer, because it doesn't demonstrate any real scenario.
However, there is a good reason for switching to another thread before return. The reason is that the workflow that calls your function (e.g. asyncMethod) will continue running in the context/thread that you switch to before returning. For example, if you write:
Async.Start (async {
// Starts running on some thread (depends on how it is started - 'Async.Start' uses
// thread pool and 'Async.StartImmediate' uses the current thread
do! asyncMethod (fun () ->
Thread.Sleep(1000) ) // Blocks a newly created thread for 1 sec
// Continues running on the thread pool thread
Thread.Sleep(1000) }) // Blocks thread pool thread
I think the pattern used in the example isn't quite right - asynchronous workflows should always return back to the SynchronizationContext on which they were started (e.g. if a workflow is started on GUI thread, it can switch to a new thread, but should then return back to the GUI thread). If I was writing asyncMethod function, I'd use:
let asyncMethod f = async {
let original = System.Threading.SynchronizationContext.Current
do! Async.SwitchToNewThread()
let result = f()
do! Async.SwitchToContext(original)
return result }
To answer your second question - the reason why SwitchTo operations return Async<unit> and need to be called using do! is that there is no way to switch to a different thread directly. The only points where you get the rest of the workflow as a function (that you can execute on a new thread) is when you use do! or let! The Async<T> type is essentially just some object that gets a function (the rest of the workflow) and can execute it anywhere it wants, but there is no other way to "break" the workflow.

Resources