-
Notifications
You must be signed in to change notification settings - Fork 605
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
Launching nanogui Screen in a separate thread #35
Comments
The errors I get on a Mac OS X (El Capitan):
|
Hi Dmitry, this is a serious issue on Macs, where the GLFW event loop is only allowed to run on the main thread (probably due to assumptions in Cocoa) -- see the GLFW web page for details. It is possible that you could do something horribly hacky to launch the event loop on the main thread and return to Python on another thread using longjmp() or so -- shudder! :) If you do that, I'd be really curious to know if it worked. |
(let me know in case my description doesn't make sense) |
No, it makes perfect sense. Thanks for the pointer and the idea (I use coroutines in a different project, so it doesn't make me shudder). I'll dig into it. Thanks again. |
If it works, it might even make sense to make this an official function of the Python bindings of nanogui (e.g. |
Ok, it seems to be working (using libcoro for context switching — contrary to what that page implies, it's using It's a bit annoying that you have to call There is a |
Hi Dmitry, that's awesome! -- the bit with I see that libcoro is mostly a portability layer for Windows, which doesn't have longjmp(). One thing I'm wondering is whether the coroutine approach is actually needed on Windows? If it just works on that platform, then my preferred approach to integrate it would be to just use longjmp() on OSX and Linux and do a no-op on Windows. Wenzel |
(or maybe even just on OSX) |
Well, the bit with I wouldn't characterize libcoro as a portability layer for Windows -- it has a lot of good stuff in there; if anything, it's a workaround for Mac/Linux not having fibers. But that's semantics. I agree with your larger point that since we only need this workaround on a Mac, it makes sense to strip it down to only what's necessary (basically, the I'll look into how to strip it down -- I haven't done this before, but I should learn the details anyway. |
Out of curiosity: CORO has multiple different SJLJ "drivers", one of them being setjmp()/longjmp() which works out of the box on OSX. What kind of extra yoga is needed in this case? Just calling these two is not enough? |
Well, at the very least you have to create an extra stack. |
Ouch, I forgot about that -- good point. Regarding RAII: could |
Thinking a bit more about the stacks -- are you sure that it's needed? The goal is really just to switch stacks -- the newly created thread begins executing Python code, using the stack that was previously associated with the main thread. The main thread enters the event loop, using the stack of the newly created thread. So perhaps you'll really just need tje two |
Yeah, I was just thinking about this -- the extra thread does have its own stack. I think you are right. I need to think a little more about it, but maybe the whole thing can be drastically simplified. |
Ok, I can't seem to get it to work with just |
Ok, I think I got it; see the same repository as before. I need to use a couple of intermediate threads (I need some intermediate stack to jump to), but it seems to work. Obviously, it's not extensively tested, but it works reliably for me (on a Mac — no idea about other platforms; not that we need them). The annoyance with the explicit |
Actually, this explicit |
Hi Wenzel, What are your thoughts on this? Do you want to build this functionality into nanogui (with 'mainloop(detach=True)' swapping threads in Mac and Happy holidays. |
I would love to have this as an option in the python library part of nanogui -- please do go ahead and submit a PR. Thanks, |
hey -- just a gentle ping regarding the PR :) |
Hey Wenzel, There was a problem with the code that I hadn't realized was there, and I haven't been able to fix it. Basically, currently the best I can offer is to do this using Dmitriy |
Hm, I'm not so excited about bundling another dependency (at least conceptually, I still feel that this should be possible with the builtin tools). What was the problem you encountered? |
I wish I knew what the problem was. It was a spontaneous segfault, occurring with different frequency in different cases. I never managed to get to the bottom of it. For what it's worth, |
I've pushed the changes I've made to https://github.com/mrzv/nanogui in case you want to take a look. |
Hi Dmitry, |
Hi Wenzel, Here's the code I used to test whether what I was doing with threading was working (slightly, adjusted for how you added
When I run it with your new code, it doesn't quite work. Sometimes it does, but sometimes it segfaults. I think at the very least I need to acquire GIL in callbacks. So for example the bindings for
but this doesn't seem to be enough. Does the above code work for you? Should it be done differently? Any ideas why it fails? Thanks. |
Actually, I was wrong. With the changes to the callback, it's working. (I was making the change incorrectly.) This is amazing. I need to study your code to figure out what you are doing differently. I could never fix up Python state correctly after the context switch. I'll experiment more to make sure no random segfaults pop up, but this is great. Why do you choose to not have detach option in C++? Fiddling with it on Mac OS X seems like a tricky exercise, with or without Python. |
Hm, I do occasionally get a segfault in the beginning. Before any GUI is shown. Perhaps, I'm doing something wrong in the initialization? |
For reference, on what Python version is this? |
I just committed some fixes for Python 2.7.x, and a tweak that always acquires the GIL before any kind of callback. Does this fix things for you? Regarding not having the detach option in C++: swapping the thread states like this is a sort of sledgehammer peration, and the only reason why it is needed is because both Cocoa and Python are extremely inflexible when it comes to multithreaded execution. In a normal C++ program there are many more ways to restructure the program to avoid this. In doubt, it's easy to pick the appropriate pieces from python.cpp, but I'm not sure I want to provide it as a default option. |
I am indeed using Python 2.7.11. The callback issue is definitely fixed. The initial segfault also hasn't triggered, but I haven't really stressed the code. Do you know why that could have been happening? In any case, thanks a lot for this. I'm going to explore the code later and try more serious examples that I originally wanted to implement. You can probably close this, and if anything comes up, I'll file a new bug, or reply here, so you can re-open. Also, understood on the C++ front. The reasoning makes perfect sense. BTW, do I understand correctly that substantial part of the magic that made this work happened through the changes in pybind itself? |
Turns out that the PyGILState is just a broken mess that the Python maintainers have themselves sort of given up (https://bugs.python.org/issue10915, https://bugs.python.org/issue15751). So the main change was indeed in reimplementing a more flexible non-broken PyGILState API in pybind11. I suspect the startup crash you've been seeing before was due to an issue where Python 2.7.x behaves differently from Python 3.x (which is now fixed): pybind/pybind11@2f6662e In any case, hopefully this all works now. :) |
There were a few more issues with some versions of python.. the latest pybind11 versions should resolve them. |
(35028da) |
I finally got to my Linux box, and I hate to report that |
I don't know what exactly the problem is, but if I enable all the machinery that you enable only on On an unrelated note, |
Ok, great to hear -- do you want to submit a PR for that, since you got it running on your machine? |
I've created PR #68. The only thing is that I haven't tested it on Windows, so who knows what happens there. |
I would like to launch a nanogui
Screen
in a thread of its own. This works as intended on Linux, but crashes and burns on a Mac. Any suggestions and pointers would be very welcome.The text was updated successfully, but these errors were encountered: