Threading differences between Haiku and pretty much all other GUIs

Coming from Windows, Mac and Linux development, the way their GUIs seem to work is that there is a GUI thread that has an event loop of some sort and all windows are serviced with events from that one thread. If something blocks then all the windows block in the app. And you can have as many worker threads as you like to do processing under the hood.

What I’ve been doing for decades is that I’ve attached the application’s data to the window objects that run in the GUI thread. And multiple windows don’t need to lock the data because it’s all in that same thread. I’ve got lots of ways of locking stuff with worker threads / gui thread. But coming to Haiku, all that breaks down. The windows are now in DIFFERENT threads and the lack of locking is catastrophic.

It occurred to me that lots of apps from other OSs that might be ported to Haiku would have similar issues and therefor there may be a “standard” way of dealing with porting apps that doesn’t mean re-writting them in invasive ways to add locking everywhere. How do ported apps approach that?

Ported apps usually don’t use the native GUI widgets, but some portable UI framework.

Regardless, the approach is the same: you can have all your UI controls target your be_application (by the use of SetTarget whenever you configure a widget to send a message), then all your messages will land in the BApplication thread, and the window thread will be used exclusively for Haiku internal messaging (window resizing, invalidation, redraw, color changes, etc).

And in the other direction, to send data to the app, you send BMessages to the window instead of sharing data with it.

Another option is to use a lock. You can for example use BApplication::LockLooper() to lock the main application thread and use that as a kind of “giant lock” to protect all your data. Lockers are recursive, so you can simply add a BAutoLock at the start of every method (it will take care to unlock the lock as needed when the function is exited), or at a few strategic entrypoints (such as each MessageReceived function). Then you essentially simulate a single-threaded environment.

3 Likes

Most ports of GUI toolkits don’t run any user code on the window threads, but only toolkit code, and access the main thread with messages and locks. So the locking and window thread management is entirely abstracted from the user of the toolkit. (Xlibe does this, for example.)

3 Likes