-
Notifications
You must be signed in to change notification settings - Fork 876
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
[Feature] Make gocv.VideoCapture thread-safe #191
Comments
Here's fun thing. Doesn't seem like it's possible:
|
I think the "correct' pattern for OpenCV, and consequently GoCV, is probably to leave the capture in a single thread, but process the @denismakogon what do you think? |
That’s the problem I’ve faced recently. Even starting multiple video captures, one per each goroutine, it still fails to read frames concurrently. |
Yeah, I'm not too sure this is possible, or needed, as long as one accepts using a different concurrency pattern. |
LockOSThread may help. |
The "proper" concurrency pattern for this really seems to be a fan-out, using a single go routine to load in the |
Seems like it's a generally good idea to call |
I agree with @deadprogram, the fan-out technique with a channel and several goroutines is what I've used to accomplish this, I'd hate to see more mutexs peppered over Go code that doesn't need it (looking at you standard library). About using LockOSThread, the problem isn't Go rescheduling a goroutine onto another thread while in a C call. It can't and has never done that. You can see here in this old issue (I've seen it other places too but this was one of the first when google'd) golang/go#8636 (comment), when a cgo call is made that thread is essentially owned by that C code (runtime can't just stop/preempt it like Go code), this is why in earlier versions of Go if you had lots of CGO calls you could accidentally create too many threads, though I believe newer versions fixed this (there was also talk about making LockOSThread mark the thread as "dirty" so other goroutines wouldn't run on it or spawn from it... don't remember if that was implemented). The issue is once the cgo call is done and we're back in go-land, if the goroutine is put on another thread and the C call is made again and that C code was using thread local storage, then you can have a problem. That's basically the biggest hurdle when using Go with C graphics libraries right now, how often they use TLS. Edit: Forgot to mention that in my use case, where I had one goroutine reading from the device and sending data over a channel for other goroutines to work on, I've never had a crash or other weird issue, and the one routine reading from the device was not using LockOSThread. |
@iaburton that was very well stated, as far as the "correct" pattern to use, and the reasons why. Seems to me that this issue can be closed now, @denismakogon what do you think? |
Thanks for the info, agree about the diagnosis of thread-local storage being the problem.
It might also be that Go runtime just happened to keep that goroutine on a single thread anyway. Only way to prove it doesn't affect it, would be to kill the thread, forcing the scheduler to start a new one for the goroutine. |
@marktheunissen That's true, such is the way of these non-deterministic things. My heaviest use time was in a couple of go/gocv/opencv versions ago, I suppose something could have changed recently in one of them too that might be causing something. Though I would still argue that it would need more investigation by those who have seen it, before adding mutexs to gocv. I guess this is slightly OT but is there an easy way to kill a thread in Go? I didn't think there was. |
Yes it's possible through grabbing the id and just doing either a call directly through runtime or by calling some kind of intermediate function. I haven't done it before but it's possible. |
I had thought the problem was the goroutine could switch threads during/after the call to get the ID, making it useless, you could potentially kill the wrong one. I think this is why they didn't expose a simple method to get the ID in the standard library. I guess you could get around that with LockOSThread but I'd suspect the goroutine would die (or panic) with it if you tried to kill the thread it was locked to, defeating the purpose of the test you propose. Would be interesting to find out though, not sure what'll happen. |
As far as I understand it, I do not think that goroutines will switch what OS thread they are executing against. The problem is that some software such as OpenCV (also SDL as a point of reference) on some platforms like macOS (also possibly might be on Windows, not completely sure) require that any GUI windows created are off of the main application thread. This is not a problem on Linux. In any case, that is just to throw in my own 25 cents. |
That can definitely be the case if you're using the GUI functions of gocv/opencv, though I would hope the video capture code doesn't automatically force that restriction too (admittedly I don't know if it does). I actually had a Go program a couple of years ago that needed to have small notification icons in the desktop of Windows/Mac/Linux and you're correct, MacOS was the most restrictive, it wanted any GUI/drawing/windowing event to be from the main thread that the program started with, Windows actually doesn't care if it's the main thread, it just wants it all from the same thread, and Linux didn't care so much as long as you didn't cause a race/memory corruption. |
So, the idea to make
gocv.VideoCapture
safe while accessing one from goroutines.Here's the use case: as developer, i want to parse a video in frames (1 chunk equals to video's FPS) concurrently, the most efficient way to make this happen to use
VideoCapture.Set
andVideoCapture.Read
.This is a sample code to do a frame reading (not thread-safe):
So, all i want is to start a bunch of these functions in parallel to speed up processing time because it make take hell of a time to process all frames from, let's say 1.4Gb, movie file.
My suggestion is:
Set
andRead
mutex-protected, similar togocv.VideoWriter
breaf solution:
The text was updated successfully, but these errors were encountered: