Swift: Async callback in command line utility [duplicate] - multithreading

I am writing a command line application in Swift using a third-party framework that (if I understand the code correctly) relies on GCD callbacks to complete certain actions when a socket receives data. In order to better understand the framework, I have been playing around with a sample Cocoa application the framework's author wrote to go along with the framework.
Because the sample application is a Cocoa application, the run loops are handled automatically. I'm including snippets of code from the sample application (MIT license) to give an idea of how it works:
class AppDelegate: NSObject, NSApplicationDelegate {
var httpd : Connect!
func startServer() {
httpd = Connect()
.onLog {
[weak self] in // unowned makes this crash
self!.log($0)
}
.useQueue(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
...
httpd.listen(1337)
}
...
func applicationDidFinishLaunching(aNotification: NSNotification?) {
startServer()
...
}
}
I'd like to modify the sample application to run from the command line. When I put the startServer() function into a command line application, it runs, but the socket is immediately closed after it is opened, and the program finishes executing with an exit code 0. This is expected behavior, as there are no run loops in an Xcode command line project, and thus the program doesn't know to wait for the socket to receive data.
I believe the correct way to get the socket to stay open and the program to continuously run would be to put the main thread in a CFRunLoop. I have looked over Apple's documentation and, except for the basic API reference, there is nothing on threading in Swift. I have looked at third party resources, but they all involve alternate threads in iOS and Cocoa applications. How do I properly implement a CFRunLoop for the main thread?

It seems like Martin R's answer should work, however I was able to get the socket to stay open with a single function call. At the end of the startServer() function, I put the line:
CFRunLoopRun()
Which worked.

The NSRunLoop Class Reference
has an example for a simple runloop:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
which can be translated to Swift:
var shouldKeepRunning = true // global
let theRL = NSRunLoop.currentRunLoop()
while shouldKeepRunning && theRL.runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture()) { }
Alternatively, it might be sufficient to just call
dispatch_main()
Update for Swift 3.1:
let theRL = RunLoop.current
while shouldKeepRunning && theRL.run(mode: .defaultRunLoopMode, before: .distantFuture) { }
or
dispatchMain()

Related

Why you can't create glfw window on another thread?

Yes I know opengl is not thread safe but what I want is run a new window with opengl in it on a different thread entirely without doing any sort of data manipulation over opengl and causing weird bugs what i want is have a web server that based on requests sent run a opengl thread render it then save it to a picture (basically im trying to render 3d virtual avatars for a website). But I kept getting this error:
OpenTK.Windowing.GraphicsLibraryFramework.GLFWException: GLFW can only be called from the main thread!
Code being (Licensed under public domain):
public async Task RenderAvatar() {
while(true) {
HttpListenerContext td = await httpServer.GetContextAsync();
HttpListenerRequest req = td.Request;
HttpListenerResponse res = td.Response;
if(req.HttpMethod == "GET") {
if(req.Url.AbsolutePath.ToString() == "/renderAvatar.3d") {
var parameters = HttpUtility.ParseQueryString(req.Url.Query);
if(parameters.Count == 3) {
var pant = parameters[0].ToString();
var face = parameters[1].ToString();
var shirt = parameters[2].ToString();
Game game = new Game(new string[]{pant,face,shirt, null},new string[]{ "head",
"neck",
"torso",
"larm",
"rarm",
"lleg",
"rleg",null});
game.Run();
}
}
}
}
after accessing the web page exception throws but I'm pretty sure it should run fine in theory since I do not do any sort of access other than initializing game type: GameWindow object with parameters taken from the query and running it.
So I want to know what is the technical reason behind glfw don't letting me to run it on a different thread even if it will work fine in theory?
If it will run fine as long as I don't do data manipulation from different thread Is theres a way to bypass the exception or can I avoid the error by Compiling OpenTK myself and removing the exception and expect it to run fine?
Most GLFW functions, including glfwCreateWindow must by called from the main thread. It says exactly that in the main GLFW reference and the OpenTK reference.
OpenGL is not GLFW. The GLFW thread rules apply to GLFW functions, and so you must respect them while calling GLFW functions. If you want to run OpenGL code in a non main thread, that is all fine.
Importantly, glfwMakeContextCurrent may be called from any thread. This means that you can make a window on the main thread, hand it off to a second thread, and the second thread can then use the OpenGL context of that window. The second thread can also call glfwSwapBuffers, but various other window functions like glfwPollEvents still must be called from the main thread.
If you are ever unsure about the thread safety of a GLFW function, check the reference and it will tell you:
https://www.glfw.org/docs/3.3/modules.html

Where Isolate can be defined in Flutter? How to start a thread in Flutter?

I am a new in Flutter, so the question can be kind of obvious, but I can't find any answer on the Internet.
I have a Flutter application with some screens and I would say on the fifth screen I have a button, which should trigger some heavy computation work (converting thousands of images). On the same screen there is a progress bar and it is supposed to display the progress.
I am puzzled how to implement that technically. The triggering is happening obviously on onPressed of the button.
if I simply call a Future<void> function, then the UI is freezing completely for the time of processing, which is obviously is not desired behavior
if I put my function inside compute, on the first await I get exception
Unhandled Exception: Exception: ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized. If you're running an application and need to access the binary messenger before runApp() has been called (for example, during plugin initialization), then you need to explicitly call the WidgetsFlutterBinding.ensureInitialized() first. which puzzles me, because I call WidgetsFlutterBinding.ensureInitialized() before runApp(). Anyway this method is not working.
compute(computationFunction, 'argument');
// ...
static void computationFunction(String argument) async {
await firstStepFunction();
// ...
if I put my function into Isolate.spawn I get exception Unhandled Exception: Invalid argument(s): Isolate.spawn expects to be passed a static or top-level function which is also puzzling me. I tried to make the function static and moved the function to the top level of this fifth screen module. Nothing changed. Am I supposed to start the Isolate at the main function? In all beautiful examples it is done like that. Can't I start the Isolate in the middle by the button click.
Isolate.spawn(computationFunction, receivePort.sendPort);
// ...
void computationFunction(SendPort sendPort) async {
await firstStepFunction();
// ...
In Java I think a simple new Thread(...).start() will do the job.
But how to do it in Flutter?
Update:
In my experiments I've noticed, that neither Flutter Hot Restart nor Hot Reload are not working correctly with isolates. You need really to run again the whole app.
I managed to start Isolate.spawn all right if async/await keywords are removed. Off course the called function should have its synchronous version. So this does not work universally.
Isolate.spawn(computationFunction, receivePort.sendPort);
// ...
static void computationFunction(SendPort sendPort) { // async removed
firstStepFunctionSync(); // the function is replaced with its synchronous version
// ...
I've found package flutter_isolate which allows to run the async functions:
FlutterIsolate.spawn(computationFunction, argument);
// ...
void computationFunction(SendPort sendPort) async {
await firstStepFunction();
// ...
I will try to use flutter_isolate package in my prototype.
You should read https://dev.to/alphamikle/why-should-you-use-isolates-in-flutter-1k5o, and look at package:isolates.
The article contrasts using main thread, compute, Isolate proper, and the isolates package, with advantages and disadvantages of each. Best article I've seen in a long time.
Also keep in mind, Java threads are data-shared, leading to possible deadlocks. Dart isolates are share-nothing, using "ports" to carefully move data between isolates, and no need for locking!
Check out this plugin, which provides an easy way to work with isolates with a worker abstraction or using Parallel methods, and has well-explained documentation.
https://pub.dev/packages/easy_isolate
The use is simple as
void main() async {
final worker = Worker();
await worker.init(mainHandler, isolateHandler);
worker.sendMessage(null);
}
void mainHandler(dynamic data, SendPort isolateSendPort) {
isolateSendPort.send(null);
}
// Top-level function (or static)
void isolateHandler(dynamic data, SendPort mainSendPort, SendErrorFunction onSendError) {
mainSendPort.send(null);
}
Or using the Parallel methods
Future main() async {
await Parallel.foreach(['test'], writeFile);
}
// Top-level function (or static)
void writeFile(String name) {
File(Directory.systemTemp.path + '/$name').createSync();
}

Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread [duplicate]

I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?
Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.
I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."

After adding multi threading to my app, VS2010 will not remove file handle after stopping debugging

today I've added multi threading to a windows forms application. On my UI thread I'm starting a thread via new Thread() {...}).Start(); Which itself will call a Method which uses ThreadPool.QueueUserWorkItem(). After the Method is called the thread will wait on a queue until a specific item is returned and the thread exits:
new Thread(o =>
{
s.SimulateChanges();
Boolean run = true;
while (run)
{
SimulationResult sr = queue.WaitDequeue();
//EOF is a static property which will be returned
//if the queue is at its end so I can break the while loop
if (SimulationResult.EOF.Equals(sr))
{
run = false;
continue;
}
this.simulationProgressBar.BeginInvoke((Action)delegate()
{
if (sr.IsDummy && this.simulationProgressBar.Value < this.simulationProgressBar.Maximum)
{
/*...*/
}
else
{
this.resultListView.AddObject(sr);
}
});
}
this.simulationProgressBar.BeginInvoke((Action)delegate()
{
this.ToggleSimulationControls(true);
});
}).Start();
And that is the code of the method called:
public void SimulateChanges()
{
ThreadPool.QueueUserWorkItem(o =>
{
foreach (IColElem elem in collection.AsEnumerable())
{
/*lot of code*/
queue.Enqueue(new SimulationResult() { IsDummy = true });
}
log.Debug("Finished!");
queue.Enqueue(SimulationResult.EOF);
});
}
My Queue is a self written class allowing a thread to wait on dequeue until an object ins enqueued.
Everything is working fine, except that if I stop debugging (using stop debugging or simply closing the application) I can't rebuild my application as VS2010 doesn't remove the file handle. I believe it has something to do with my threads not exiting correctly. Is their any way I can assure this?
Thanks for any advice :-)
Hard to explain all aspects of the question. But you are making a pretty common mistake, often made by programmers when they first start using threads. You are not making sure that the thread stops running when the user closes the main window. It is an easy mistake to make, the UI thread takes care of a lot of grunt work. Including automatically terminating when the main window of your app is closed by the user. So at least part of your problem is that you did manage to close the main window. But didn't actually terminate the process. Building cannot work, your program's EXE is still in use.
Properly shutting down a thread can be very difficult, given that the user will close the window regardless of what that thread is doing. It could be catatonic, buried deep inside an operating system call and waiting for it to complete. Tough to ask it to quit when it isn't executing code.
There is a very simple solution, at least good enough to keep going with your project or solve half the problem you have. You can mark the thread as "kill automatically at program termination" and the CLR will take care of it. Use the IsBackground property, like this:
var t = new Thread(o =>
{
// Lotsa code
});
t.IsBackground = true;
t.Start();
But do keep in mind that there's nothing graceful about that kind of kill. If you are writing a file or talking to a server then that's going to cause a partially written file or a very confused server. Otherwise not different from killing the program with task manager.

Is there some kind of equivalent to .NET's BackgroundWorker in Vala?

I'm trying to learn Vala so I'm making a small GUI application. My main language before has been C# so things are going pretty well.
However, I've hit the wall now. I need to connect to an external network server (using GIO) which doesn't answer my client immediately. This makes the GUI freeze up while the program is connecting and doing its thing.
In C# I would probably use a BackgroundWorker in this case. I can't seem to find anything like it for Vala though.
Basically, I have a MainWindow.vala where I have hooked up a signal for clicking a certain button to a method that is creating a new instance of ProcessingDialog.vala. This shows a dialog over the MainWindow that I want the user to see while the program is doing the work (connecting to the server, communicating).
What are my alternatives to make this scenario work?
GIO offers async methods, see an async client for example: https://live.gnome.org/Vala/GIONetworkingSample
If you are not aware of async methods in Vala, try looking at the tutorial: https://live.gnome.org/Vala/Tutorial#Asynchronous_Methods
lethalman's answer above probably makes the most sense, an async request is really going to be your best bet if you're doing a network call. In other cases, you can use Vala's built in thread support to accomplish a background task. It looks like soon enough, there will be a better library available, but this is what's stable.
// Create the function to perform the task
public void thread_function() {
stdout.printf("I am doing something!\n");
}
public int main( string[] args ) {
// Create the thread to start that function
unowned Thread<void*> my_thread = Thread.create<void*>(thread_function, true);
// Some time toward the end of your application, reclaim the thread
my_thread.join();
return 1;
}
Remember to compile with the "--thread" option.

Resources