Open changkun opened 3 years ago
I am new to fyne and was working on some UI project using fyne, where I came across a lot of data race problems.
I don't think it's easy or even feasible to make all public methods/fields concurrent safe.
What I need is simply a RunInUIThread(callback func ())
method that allows me to run all UI related code to the UI goroutine.
I think it's a very common pattern in UI frameworks? Why doesn't fyne have that?
I don't think it's easy or even feasible to make all public methods/fields concurrent safe.
Methods yes, fields maybe not - but we are working hard on this. The idea is that the toolkit does all the hard work so that developers don't have to!
I think it's a very common pattern in UI frameworks? Why doesn't fyne have that?
Basically because it's a horrible pattern that feels like a workaround - and certainly not very clear to people learning to code an app. In the cases where it is impossible to avoid a race without it we may have to consider something (discussions have been going on for a long time about how best to do so).
I was reading through the discussions on thread safety and I think that with the current API design it is impossible to make access to some public fields free of race conditions - though the chance that such race conditions can occur can be made "negligible". All public string fields for instance cannot even be copied in a race-free way since a string is two machine words long (a pointer and a size). However for the race to occur a user goroutine would need to assign to the field in between when the length and pointer values of the string were copied.
It may be worth thinking about deprecating public fields (at least string fields) on widgets/CanvasObjects and forcing all user access to go through getters/setters. Unfortunately it makes the API a little verbose and is a large breaking change (since the way extended widgets are initialized would need to change). Another option would be to add getters and setters for all the public fields but leave them exported, with a comment specifying that they should only be directly accessed on widget construction. Though we are definitely OK with deferring these considerations for quite awhile as the chance that this kind of data race would occur is very very small.
Edit: bluebugs' WidgetState proposal above might work, and the signature of the Update function could possibly be simplified just to Update(FooWidgetState state)
, the internal implementation would acquire locks as appropriate to set the private widget state in a race-free manner
It may be worth thinking about deprecating public fields (at least string fields) on widgets/CanvasObjects and forcing all user access to go through getters/setters. Unfortunately it makes the API a little verbose and is a large breaking change (since the way extended widgets are initialized would need to change).
This is indeed one of the discussions about how we would "completely fix" races and for the reasons you state it's being considered for the v3 API.
Edit: bluebugs' WidgetState proposal above might work, and the signature of the Update function could possibly be simplified just to Update(FooWidgetState state), the internal implementation would acquire locks as appropriate to set the private widget state in a race-free manner
Agreed, this simplified version could be a good approach as well.
I am considering exposing some internal lock handling (UpdateFieldsAndRefresh
and maybe GetFields
) which would allow people to safely use fields if it really matters to their code. That could tide us over and then we could concentrate on eliminating the internal issues that are more pressing.
I am not a Professional programmer, but I see another solution to the race conditions. In case fyne internal race conditions are fixed, it should not be allowed to update content from other goroutines. And this is it. For dynamical content update user should be able to define function that would be triggered synchronously by fyne. If user has some goroutines generating actual content, they can share it through channels with this special function.
Describe the bug:
Run fyne_demo with
-race
flag:go run -race main.go
OutputWe should enable data race detection in the tests.
Device (please complete the following information):