-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cross Thread Access #4
Comments
A decision on this might also be influenced by how haxe coroutines are going to handle suspendable functions potentially changing which thread a coroutine would continue on. |
Had an idea the other day which might solve several questions around threading, lifetimes, and some coroutine stuff. I've been operating on a 1 haxe thread, 1 libuv loop principle. But what if there was a dedicated background thread which just ran the libuv loop and which all asys api calls were serialised onto. I think this approach solves several problems. Cross thread usage. You no longer have the limitation of asys objects only being usable on the thread they were created on. Passing asys objects around threads might seem odd but given that there as been a fair bit of discussion about coroutine scheduling, it might be possible for coroutines to resume on a threadpool which means asys objects being usable across threads is important and this approach would allow that. Resouce management. A single libuv thread owned by the runtime makes object lifetimes much easier. If close hasn't been called by the time the asys object get finalised, it's easy to schedule the close on dedicated the libuv thread. You no longer have to worry about tracking haxe threads, which objects were created on them, is that thread still alive, etc, etc. Not tied to the thread event loop. This would also free asys from the thread event loop and would allow a much easier blocking start implementation in coroutines. Basing this off my recent coroutine experiments and assuming the coroutine asys wrappers shuttles the callbacks through the coroutine scheduler, start could create its own EventLoop and pump that between checking for results. This way its true blocking, instead of the thread event loop pumping we were thinking of before which could cause other code to be executed. There are potentially some downsides though. This approach would probably work fine for hxcpp and hl where they have their own runtime, but if another target which doesn't really implement its own runtime and wants to use libuv for its implementation, that might make things a bit more difficult. This single thread could become a bottle neck as work will have to be placed in some sort of thread safe collection which can be picked up by the libuv thread to process. This might not end up being a problem under normal conditions though. |
This is probably more coroutine related than asys but it's a follow on from the above comment so I'm putting it here. Played around with the global libuv loop idea and it seems to work well, converted a very small subset of my asys stuff to use it (file open, write, and close). A coroutine implementation of @:coroutine public static function openFile<T>(path:FilePath, flag:FileOpenFlag<T>):T {
if (path == null) {
throw new ArgumentException('path', 'path was null');
}
return Coroutine.suspend(cont -> {
cpp.asys.File.open(
path,
cast flag,
file -> cont.resume(@:privateAccess new File(file), null),
error -> cont.resumt(null, new FsException(error, path)))
});
} The This makes implementing a blocking coroutine // possible `start` implementation.
final loop = new EventLoop();
final blocker = new WaitingCompletion(loop, new EventLoopScheduler(loop));
final result = switch myCoroutine(blocker) {
case Suspended:
// wait will pump the provided event loop until its `resume` is called indicating the coroutine has completed.
blocker.wait();
case Success(v):
v;
case Error(exn):
throw exn;
} An enhancement / slight alternative to this global loop which might help libuv integration with other targets could be to have some sort of I've created a new branch in both my hxcpp fork and hxcpp_asys repo with this small global loop test. |
Take the following contrived example, the user opens a file and then spins up a new thread (for some reason) to perform a write on it.
Might seem a bit odd given that async functions are supposed to avoid dealing with thread manually, but nothing seems wrong with this, with the exception that libuv doesn't allow it.
Libuv is not a thread safe API, you can only access handles on the thread they were created on which means the above sample won't work. I think there are probably two main things we could do here.
InvalidThreadAccessException
to the callback if called from a different thread. This is much easier to implement but would probably seem a bit odd to most users. This limitation is also imposed by libuv and may not be true if other implementations are not libuv based, but they would still have to implement this behaviour as it seems too big to be left as target defined.The text was updated successfully, but these errors were encountered: