-
Notifications
You must be signed in to change notification settings - Fork 18k
syscall: unexplained crashes when using win32api (PostMessage + Window functions) #50872
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
Comments
You need to use this: Otherwise there is a chance that you will not be on the main thread when the windows GUI code executes, which is not allowed. After startup, the Go runtime can switch threads transparently. |
Hi @beoran , All this package does is call |
Please study that package in detail. Timing and functionality are crucial. Lockosthread must be called in an init function, and then you have to post callbacks on a channel to be sure that you are on the main thread. Once in the main function the go runtime might already have started another thread. If you don't understand the details then by all means it is best you use that package and call the windows GUI API from that package's Run function. |
I haven't taken a close look, but yes, anything that requires running on the main thread (like most GUI-related things) requires some special care, and it's more subtle than you might think. The precise steps are:
This is exactly what https://github.com/faiface/mainthread does, but it wraps it in an API. Given that this is well-understood, I think that explains what could be going wrong with your program. If you have a reproducer that only relies on Leaving this open for the moment as waiting for info. |
Hi, in my case call |
Although this issue was closed, perhaps it should be documented somewhere a bit better what running on the main thread is and when, why and how it should be done? Perhaps in the lockosthread documentation? |
@beoran See #23112 and https://pkg.go.dev/runtime#LockOSThread. I'm not sure where else this should be documented, but if another place feels better to you, then let us know. Or you can send us a PR as well. :) |
It could be added there that it is necessary to lick and use the main thread for Windows and Osx GUI calls and that on Unix/Linux the thread that connects to X11 or Wayland needs to be locked and used for future calls. As for a PR. I oppose CLAs for floss, so I cannot contribute to Go except by giving suggestions here. A DCO should be sufficient. ( http://esr.ibiblio.org/?p=8287) Once you allow people to contribute with a DCO, I definitely will join in. |
I don't think the documentation is missing, but a little more detail would be nice. For example, why does calling As I understand it, the goroutine I am calling is supposed to prevent it from switching to another thread etc , but I seem to have misunderstood this. As another form of question: Is |
Lockosthread also works later on, but it may lock the goroutine to a non main thread from which you cannot call Windows GUI functions. |
What version of Go are you using (
go version
)?go version go1.17.3 windows/amd64
windows 10 64bit
Does this issue reproduce with the latest release?
I don't know, I haven't tried it with beta versions or older versions.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
After long test I decided to share this. In this way, maybe a solution can be found, or this is the cause of an error in Golang's runtime.
Here I am summarizing the issue so that everyone can understand what I want to do:
Let's create a simple Win32api application. I will share an example program below.
We don't use cgo. We will use syscall.
The Win32api function
GetMessage
blocks the program if there are no messages in the event queue. So if no event is created, the program waits forever for an event to occur.So I'm sending messages to the queue with
PostMessage
. I do this withtime.Ticker
.Now we have prevented the program from being blocked forever. We can receive the events we send with PostMessage from the queue.
As a note, PostMessage runs another goroutine. Using
runtime.LockOSThread
does not prevent the program from crashing.The program can run without anything for a long time. Sometimes it crashes with no errors. Sometimes it works normally for a very long time, sometimes it crashes immediately. Finally, after a certain time, the program stops responding.
This made me think about the possibility of race condition. But there is no such thing.
I wrote a duplicate of the same code in C++. Win32api shows no problems. The program never crashes. I know that C++ and Golang are not the same thing. I just wanted to understand where the problem is.
So the program not crashing in C++ makes me think that Golang is doing something wrong for win32api in runtime.
My guess is that he is moving the runtime goroutines to different threads or dealing with a similar golang thing. Some win32api functions are sensitive to the called thread. In other words, the thread that the goroutine is connected to should not change. Maybe GC is deleting something important for win32api. I really don't know what's going on here.
I tried to keep this issue simple so anyone can generate it themselves but since win32api is a low level api it takes a long time to create something.
Those who want to confirm this example can run the program and wait. You can leave the program's window and switch to something else. Because sometimes it works right for too long for incomprehensible reasons.
I don't know how to test this in a simpler way.
Go code (go build app.go):
C++ (g++ app.cpp):
What did you expect to see?
The program should not crash.
Ok, a program can crash anytime. But it should not crash sporadically, for no reason. I want to know the problem here.
What did you see instead?
I see a program crashing at unpredictable times.
Sometimes it works correctly for a very long time. Sometimes it crashes within 1-2 minutes.
I think the crash was caused by a component that started running in the runtime. Maybe gc is kicking in or something.
I am apologize for my English. It's not my native language. I hope the codes I shared describe the problem better.
The text was updated successfully, but these errors were encountered: