Bug: libsdl not thread-safe |
Carlo Wood
Guest
|
If SDL_PollEvent and/or SDL_PumpEvents are used/needed instead
of using libsdl's "event thread", then the SDL_EventThread is NULL. In that case SDL_Lock_EventThread and SDL_Unlock_EventThread does nothing, and libsdl does calls to libx11 without setting any lock, ever. As a result, it is not possible to use libsdl by using SDL_PollEvent and at the same time using either libsdl or libx11 from more than one thread, except by wrapping every SDL call in a display lock as well as libx11 calls... -- Carlo Wood _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
On Sun, Jan 17, 2010 at 9:27 PM, Carlo Wood wrote:
I can't figure out what you are saying here. SDL_PollEvent and SDL_PumpEvent are APIs. A thread is a thread. You can't use an API instead of a thread. You are going to have to be more clear before I can help you.
That is correct, SDL pretty much assumes that the main thread will do the rendering and handle input events so it does not need to lock libx11.
Mixing SDL and direct calls to libX11 is not a good idea. OTOH If you want to use libx11 directly from a multithreaded program read the docs on XInitThreads(). If you don't call it libX11 will not be thread safe. Which version of SDL are you using? Bob Pendleton
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||||
|
Bug: libsdl not thread-safe |
Sam Lantinga
|
SDL_PollEvent(), SDL_WaitEvent() and SDL_PumpEvents() may only be
called on the main thread, for the reasons you mentioned. You can use SDL_PeepEvents() on any thread, since it only interacts with the event queue and is defined to be thread safe. I'll make that more clear in the new wiki documentation. Thanks! On Sun, Jan 17, 2010 at 7:27 PM, Carlo Wood wrote:
-- -Sam Lantinga, Founder and President, Galaxy Gameworks LLC _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|
Bug: libsdl not thread-safe |
Carlo Wood
Guest
|
On Mon, Jan 18, 2010 at 03:03:31PM -0800, Sam Lantinga wrote:
That is not the point that I was trying to make. If an application uses SDL_PollEvent() from it's main thread, then that implies that no locking occurs for libx11 calls (by libsdl). Therefore, such an application cannot do libx11 OR libsdl calls from any other thread. I consider this a bug; libsdl should make it possible to use SDL_PollEvent() (from the main thread) and still have (custom) locks around every call to libx11. The case where I ran into this is the Second Life viewer, which does all it's rendering in it's main thread and has it's own mainloop, calling SDL_PollEvent() from that loop as well. At some point, someone can open a "file chooser" (ie, to pick a texture or sound file for upload). The file chooser is implemented with GTK, which "requires" calling gtk_main(). If that is done from the main thread then the main loop freezes completely, no rendering of anything else is done anymore, but worse, the network packets from the server aren't handled anymore and the viewer pings out and disconnects if one keeps the dialog open too long. In order to avoid that one has to run this dialog in it's own thread therefore. However, the dialog somewhere causes calls to libx11: so, now we have on one hand the demand to do calls to libx11 from another thread than the main loop and on the other hand libsdl calls from the main loop that do NOT lock the X display. Result: X message buffer corruptions and a crash. There are only two solutions: 1) Wrap all calls to libsdl in a lock/unlock yourself, 2) Consider this a bug and fix libsdl so that EVEN if it doesn't run an "Event Thread", it STILL does locking (preferably by calling user provided functions). -- Carlo Wood _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|
Bug: libsdl not thread-safe |
Donny Viszneki
Guest
|
On Mon, Jan 18, 2010 at 7:45 PM, Carlo Wood wrote:
Please forgive me if I seem to be missing your point, but couldn't you solve the problem by, you know, creating a lock, and making sure you implement your own locking policies around libx11 and SDL APIs? Perhaps the problem is that you don't know what SDL APIs may ultimately make an x11 call? Adding locks into the SDL API would add unnecessary overhead for the most common case: developers who are not accessing the API from a single thread, using other threads for doing *other work*. -- http://codebad.com/ _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|
Bug: libsdl not thread-safe |
Carlo Wood
Guest
|
On Mon, Jan 18, 2010 at 08:34:05PM -0500, Donny Viszneki wrote:
If that is the only way, then it would certainly help if it were documented which sdl APIs need that lock.
But you are *already* calling lock/unlock functions in all the right places, it's just that these functions don't do anything. The following code would not slow down libsdl but allow to use those calls: Instead of the existing code: void SDL_Lock_EventThread(void) { if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) { /* Grab lock and spin until we're sure event thread stopped */ SDL_mutexP(SDL_EventLock.lock); while ( ! SDL_EventLock.safe ) { SDL_Delay(1); } } } Which is exactly the same as: void SDL_Lock_EventThread(void) { if ( SDL_EventThread ) { if ( (SDL_ThreadID() != event_thread) ) { /* Grab lock and spin until we're sure event thread stopped */ SDL_mutexP(SDL_EventLock.lock); while ( ! SDL_EventLock.safe ) { SDL_Delay(1); } } } } one could do: static void (*SDL_CustomLock)(void); void SDL_Lock_EventThread(void) { if ( SDL_EventThread ) { if ( (SDL_ThreadID() != event_thread) ) { /* Grab lock and spin until we're sure event thread stopped */ SDL_mutexP(SDL_EventLock.lock); while ( ! SDL_EventLock.safe ) { SDL_Delay(1); } } } else if ( SDL_CustomLock ) { SDL_CustomLock(); } } And add an API to set this lock function (pointer). Same for SDL_Unlock_EventThread of course. That would solve the issue (assuming non-SDL_EventThread threads in libsdl do not lock SDL_EventLock directly anywhere but always use SDL_Lock_EventThread(), which seems to be the case). -- Carlo Wood _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
I know I said this before, but take a look at XInitThreads(). If you
do not call XInitThreads() then you can not make Xlib calls from multiple threads. It doesn't matter if you wrap Xlib calls with your own locks. You must call XInitThreads. Before this discussion goes any further I think everyone needs to examine their assumptions. The assumption that the current design of SDL and Xlib are bugs are the ones I would examine first. Bob Pendleton On Mon, Jan 18, 2010 at 6:45 PM, Carlo Wood wrote:
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||
|
Bug: libsdl not thread-safe |
Donny Viszneki
Guest
|
On Tue, Jan 19, 2010 at 7:57 AM, Carlo Wood wrote:
You're right. I think the reason SDL has resisted exposing the internal locking mechanisms is because the APIs which might lock anything probably can only be safely called from the main thread due to constraints we can't help on many platforms. I vote in favor of exposing more of these locks for applications to incorporate platform-dependent functionality via non-SDL calls, for instance xlib.
Yuck. Do we have the necessary concurrency primitives in SDL to begin removing stuff like "while(!SDL_EventLock.safe) SDL_Delay(1)?" -- http://codebad.com/ _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
On Tue, Jan 19, 2010 at 12:33 PM, Donny Viszneki
wrote:
Yeah, if you are going to use a spin lock then you might as well use the atomic operations. :-) But, yeah, seriously, why would you have to spin after you grab the lock. If you have the lock, no one else has it and it is safe to enter the critical section. Why spin after you lock the lock? I can using a condition to tell you that the lock is locked and then spin back to the condition if you don't grab the lock when you come out of the condition, I've used that one my self many times. Bob Pendleton
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||||
|
Bug: libsdl not thread-safe |
Carlo Wood
Guest
|
On Tue, Jan 19, 2010 at 07:48:42AM -0600, Bob Pendleton wrote:
Well, you're wrong. X11 (the protocol) is not thread-safe, and libx11 is not thread-safe (reentrant) period. Xlib is the software solution to make X11 "thread-safe". It needs an initialization before you can use it that way however, by calling XInitThreads(). XInitThreads is a function of Xlib, not libx11. I'm not using Xlib nor do I want that. Adding your own locking around sets of commands + a call to XSync does the job fine, and this is how libsdl does it too (look at your own code). Anyway, it seems that Donny Viszneki does understand what I'm trying to say. Maybe he can explain it more clearly then me. -- Carlo Wood _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
On Tue, Jan 19, 2010 at 4:39 PM, Carlo Wood wrote:
X Window System Protocol Version 11 is a protocol not code. It can not be either thread safe or thread unsafe. There is in fact a very nice library designed to use the X Window System Protocol Version 11 in an asynchronous way from multiple threads. Oh, BTW, you seem to be a bit hung up on names so I'm trying to use the correct names everywhere not matter how much extra typing that requires.
That is correct. I did not say that it was. I said that if you want to use it from multiple threads you have to tell it that you are going to do that by calling XInitThreads. I made the sad assumption that if you were aware of XInitThreads you would also know about XLockDisplay() and XUnlockDisplay() and know that they are the correct way to look access to the library. I also assumed that if you were not aware of the standard method for using Xlib from multiple threads you would look it up. Clearly I was wrong.
No, it is not. It is the name for the lowest level library provided for generating and receiving messages using the X Window System Protocol Version 11. Xlib is commonly used to refer to both the source code and the compiled library. Xlib does contain minimal support for multiple threads.
Nope, XInitThreads() is in libx11. libX11 is the name of the library file you get when you compile Xlib on a Unix like OS such as Linux. The name of the compiled Xlib is not, to the best of my knowledge, part of the standard.
Calling Xsync causes a round trip to the server. The calling thread is forced to wait while the round trip takes place. While that thread is waiting no other thread can use Xlib. That means that Xsync is the opposite of what you want to use in a multithreaded program. Using your own mutexes is a bad idea because you can't be sure that other parts of the code, parts of libraries you have linked in, are not making their own multi-threaded calls to Xlib. To make sure that Xlib is actually being accessed properly you must use SinitThreads() and Xlibs own lock and unlock operations. Now it is possible that Sam has put in code that does just what you say it does. Its been a while since I looked. But it wasn't that long ago that I grep-ed the whole damn source code of SDL 1.3 for Xsync and Xflush calls and Sam and I discussed everyone of them that looked suspicious to me. They were all used properly. But, like I said, maybe Sam snuck something in on me.
Yeah, maybe he can. Clearly I don't know what I'm talking about. It is funny, when I went to look up XInitThreads I grabbed my first edition "The X Window System in a Nutshell" and it wasn't in there, I had to grab my more recent edition of the O'Reilly "Xlib Programming Manual" to find it. There was no support for multithreading in Xlib when the first edition was published. I really only keep the first editions as souvenirs. They are pretty badly out of date. Back then I was on the X consortium board, Tim sent first editions of all his X books to everyone on the board. I ported X to a bunch of different computers. I did the first 24 and 32 bit versions of the server and the first server to support 1024x786 and larger resolutions. I designed and implemented the first overlay extension for X. It did not make it into the standard. I also implemented the first extension for changing the virtual window. It required an extension because we changed the pixel depth as well as the virtual screen. Lets see, I'm pretty sure I did the first X server to support stereo (quad buffered 32 bit). Yeah, that was a long time ago. Clearly I don't know shit about X. Thanks for pointing that out to me. Bob Pendleton
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||||||||||||
|
Bug: libsdl not thread-safe |
Carlo Wood
Guest
|
On Tue, Jan 19, 2010 at 07:21:17PM -0600, Bob Pendleton wrote:
I meant that the ordering of the messages is important, you can't hussle the messages of two different threads and send them to the X server.
I never coded for X directly in my life before, so it was not unlikely that I made some errors :p Thanks for pointing this out. I looked up the webpages again that I read from which I had gotten the idea that there were two different libs, and there aren't, I read it wrong. Thus, you're right that my current implementation (even though it works in my case) isn't the correct one and I'll replace my own mutex with calls to XLockDisplay() / XUnlockDisplay(), and add the initialization call. [..snip..]
*blink*. I never said that. I just think we have some communication problem because the essention of my post is still true and the story of XInitTheads / XLockDisplay / XUnlockDisplay doesn't change that. Since Donny clearly understood what I meant I thought he might be able to help here.
Libsdl does not allow a user to use Xlib from multiple threads, because it doesn't call XLockDisplay() / XUnlockDisplay(). However, it DOES call SDL_Lock_EventThread / SDL_Unlock_EventThread. So, in order to allow users to use it in a multi-threaded application you might consider revealing a bit more of this locking to the user by allowing him to specify two function pointers that will be called; or even just call XLockDisplay() / XUnlockDisplay() yourself at all times if they are X11 users... The argument that most people don't need it might not be that relevant if the each call only locks a mutex; that should be totally neglectable. Otherwise just add this to SDL_Lock_EventThread: if (sdl_thread_safe) XLockDisplay(); (the complement) and allow the user to toggle the global boolean 'sdl_thread_safe' (checking that boolean probably blends in with the rest of the assembly instructions and will be executed in parallel with existing code, and therefore cost 0 cpu cycles if sdl_thread_safe is false; otherwise it will cost 1 cpu cycle...) My original request was to add this *especially* for the case where SDL_EventThread == NULL. If you want to support thread-safety also when SDL_EventThread != NULL, you'd have to call XLockDisplay() / XUnlockDisplay() a lot more often (namely in the event thread, everywhere where currently SDL_EventLock is locked). Is this really such a performance hit? Somehow I have the feeling that sending a message over a socket completely overshadows the locking of a mutex, not to mention that if XInitThreads() isn't called, XLockDisplay probably does the same as SDL_Lock_EventThread (nothing). -- Carlo Wood _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
On Wed, Jan 20, 2010 at 7:57 AM, Carlo Wood wrote:
minute to teach a class that required me to have a Windows development environment. Reinstalling windows from the restore disks should not have taken much more that a day... But, the restore disks didn't have the drivers. After I got the drivers the first reinstall was undone by my leaving an unprotected Windows machine on the Internet. Ok, so I figured out the misconfiguration of my router/firewall... Then the hard drive made this interesting noise. After getting a new drive the video card started showing green random green dots. New video card.... New power supply to support the card. And, I still had to do all the prep for the class. I was a founding member of the First Church of Murphy... Now, back to the problem at hand. I believe there is more here than either of us thought there was.
That is correct, it doesn't. This hasn't been a problem in the past, but it is one now. It will become even more of a problem in the future. The more cores, the more the desire to use them. :-) If used properly a multithreaded X program can have multiple entities all updating the screen at the same time. This is something that you can not do on many other OSes. OTOH, you do pretty much have to have a single thread reading events coming back from the X server. But, once they are received they can be distributed to any entities that are interested in them.
This is a deeper problem than that. Wrapping the SDL event functions in a mutex is pretty straight forward and does yield significant performance improvements. It is well worth doing. (Take a look at http://gameprogrammer.com/fastevents/fastevents1.html where I did just that back in '02.) There are very good reasons why this is not a standard part of SDL 1.2. Not so sure about 1.3.
There are two reasons why SDL_EventThread will ever be NULL. The programmer can say he does not want to use a separate event thread, or the OS may not support reading events in a separate thread. IIRC Windows was the main OS that doesn't support reading events in a separate thread. It is kind of important that SDL supports Windows. Multithreaded access to graphics is a different problem. Each X protocol message contains all the information needed to identify its context. That means that so long as you set up Xlib to be thread safe you can send commands from as many different threads as you like. That is not true for OpenGL. Unless you are talking to a machine other than the one running the application OpenGL calls do not create X protocol messages and they do not identify their context. OpenGL is modal and each thread must create, maintain, and select its own contexts. To me it seems that we have more than two distinct problems. The problem of making multithreaded access to Xlib work well with the SDL event system is not one of the problems. Let me describe the problems as I see them SDL is a cross platform library designed to support portable applications. SDL APIs must work the same way on many different operating systems and graphics systems. That means that we can not ever look at a problem on just one system. We have to make sure that what we do can be made to work on other platforms. How do we make the SDL event system work nicely with multiple threads even when there is no separate event thread. I believe Sam has solved this in 1.3, but I'm not sure. We must be sure that we can have multiple threads sending events through the event system even if you do not have, can not have, an event thread. No matter what, you really can't have more than one thread reading events. It just doesn't work. How do you support multithreaded access to the graphics system even on systems where the OS or the API do not support that way of using the graphics system? Well, really, you can't. At least not without adding a new layer to the API. But, in the case OpenGL and X we can use a context (and window) per thread for OpenGL and we can make Xlib callable from multiple threads. We don't do that by adding X locking calls to the SDL event thread. We do that by adding the calls to the XLib wrappers created by SDL to call into the Xlib dynamic library. We do have to make sure that the XGL calls used to set up OpenGL are performed at the right times. But, that can by handled by xsync or xflush as they already are. You have raised an interesting issue. Being able to make Xlib calls from multiple threads would be a nice feature to have. Bob Pendleton
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||||||||||||||||||||||||
|
Re: Bug: libsdl not thread-safe |
Bug: libsdl not thread-safe |
Bob
|
On Sat, Jan 30, 2010 at 5:01 PM, nfries88 wrote:
Yes, you can do that. It is not a bad idea. That is pretty much what X actually does. Here is the problem, an API like OpenGL has *many* function calls. To do what you are proposing requires that you create a function with the same name as every OpenGL function, that is, you have to create a one to one mapping from your version of the API to the OpenGL API. Your functions have to place a struct with the arguments of the function call and the ID of the function call onto a queue. At the other end of the queue is an interpreter that reads these structs and calls the correct OpenGL function. That code records the results of the call and puts them on a queue along with the ID of the call so that if a return value is needed it can be passed back to the originating call. Aside from the amount of work involved do that is not a technically challenging problem. The technical challenge is in dealing with how many of the APIs expect to immediately return a value to the calling function. Each function that returns a value forces a round trip. That means, you have to put the function arguments on the queue and then wait for the results of the call to be returned on on the return queue. Getting performance in a system like that is difficult. If it were easy there wouldn't be a direct rendering system that bypasses the X server. It is true that on systems with two or more processors you can get good 3D performance using a server like architecture. But, with two processors you be about the same performance as you get with one processor using direct rendering. (I first ran into the problem back in the late '80s and saw the effect of multiple processors on the problem around '90.) IMHO the right solution is to turn most of the X server into a device driver. Then the problem just goes away. I saw that done in the early '90s and it worked very well. In my opinion the correct solution for SDL is to create an ultra high level graphics API, or adopt something like Open Scene Graph, and use that as a solution to the problem. OTOH, that would kind of kill the *simple" in Simple Direct-Media Library :-). I think this is a problem that can only really be solved by dropping support for platforms without fully multi-processor capable OSes and APIs. You can then add platforms as they become complaint with the needs of SDL. Does that fit in with the SDL ideals and philosophy? I don't think so... but Sam has been dropping a bunch of platforms from 1.3 so we'll see. Bob Pendleton
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com |
|||||||||||||||
|
Bug: libsdl not thread-safe |
Paulo Pinto
Guest
|
Maybe it is just my lack of graphics programming experience on real world projects, but I still fail
to see what is the problem to have only one thread taking care doing the graphics calls, while all the others do whatever they need to. This is the way it works in most GUI toolkits anyway, because of the added complexity to do it otherwise. -- Paulo On Mon, Feb 1, 2010 at 6:31 PM, Bob Pendleton wrote:
|
|||||||||||||||||
|
Bug: libsdl not thread-safe |
Bob
|
On Mon, Feb 1, 2010 at 11:49 AM, Paulo Pinto wrote:
I agree with you. If you stick around long enough you will get sick of this topic. It comes up fairly frequently. This time is started a little differently and it actually lead to identifying a "problem" that I find interesting. It usually follows a slightly different plot arc. What follows is my opinion, I can make a very strong argument for it, and it is based on my experience and education as a programmer and as a teacher. But, it is still my opinion.... Consider the fact that human males are much more likely to die of accidents than are human females. Why? Well, I've seen a guy climb down 1o floors on the outside of a hotel to recover a womans shoe. He then climbed back up to deliver the shoe to her on the balcony from which she threw it. He had made some absurd claim about how much he wanted her. So, she threw her shoe over the balcony and challenged him to "fetch". What level of stupidity causes a human male to risk his life rather than back down? The same trait leads to some truly unique bug reports. Think about the first time you (not the guy I'm replying to, the everybody version of you) tried to write a game with NPCs in it. I'll just call them actors. The usual first approach to writing an actor leads you to write a loop. Inside the loop you write a whole series of complex, nested, nasty looking if statements. The Ifs test variables in the world and lead to code that changes variables and then to code that draws the actions that result from the decision. Then you go back to the top of the loop and start over. If you pound on that code long enough and hard enough you can make it work. You can make it work for one actor. When you need to handle more than one actor you find that only one actor gets to move at a time because each actor keeps control until it has animated its last decision. You used to see commercial games that showed exactly that kind of behavior. You still see it in a lot of flash games. So what do you do when you find out that your approach can not work? Well, you try to find a way to make it work. The first approach is to jump at threads as a solution. It seems natural to just have a thread per actor so they can all move at once. But, then you find out that doesn't work either because no matter how many threads you have you can only have as many active threads as you have cores (or hyperthreads). So only a few of your actors can move at once. (Threads might also cause you some memory problems if you have a large number of actors.) But, not only don't they move at the same time, but the graphics doesn't work. It doesn't work because the graphics system was *designed* so it would not work. Depending on how clever, and stubborn, you are can keep trying to make it work. But, eventually you run into that last wall. The one that stops you cold. You project does not work and can not work. What do you do know? You have painted yourself into an emotional corner. You have invested a lot of time and effort into something that does not work. In fact, you have invested all that time and effort into something that *can*not* work. It can't work because of the basic design of OpenGL, or X, or DirectX, or whatever you are using. At this point you have a couple of choices. 1) You can accept that maybe the people who designed all that broken stuff knew what they were doing. If you do that you have to admit that you not know as much as they do and also accept that you have to throw all that work away and start over. Or, 2) you can chose to believe that the designers of all that other stuff are complete idiots. You can decide that their entire design was based on stupidity. If you believe all that you can demand that they, or someone else, fix their code. Choice #2 is normal human adolescent male behavior. It is very common human *adult* male behavior. Even women will fall into that behavior pattern at times. Choice #1 is the behavior you hope to see in a seasoned professional who has been schooled in the ways of egoless programming. It is in fact the behavior of Saints and Bodhisattvas, not that of normal human males. (It is a shame that no one teaches egoless programming anymore.) Choice #1 leads to learning about state machines, event driven programming, and an understanding of how to subdivide decisions from actions. It might even lead to an understanding of how to use threads. It is rarely the choice that is made the first time, or even the second time, you run into the impossibility wall. Choice #2 is made even more likely in the case of young male humans because they have probably spent a lot of time bragging to their friends about their great game and how close they are to being done with it. Young males have been known to find new friends rather than have to admit that they had to throw away several months worth of work. I do believe that this basic flaw in the character of human males is the reason why so many of us die before the age of 18. We are just to stupid to admit we don't know everything. To stupid to admit we said something really stupid. We would rather climb down 10 stories on the outside of a building than admit we said something stupid. (That was *not* me. I would have laughed and walked away.) Too stupid to even notice we are doing something suicidal for no reason at all. Sad to say this is all from personal experience. Been there, done that. After the second or third time I learned to write small test cases to verify every technique I was going to use before I committed months of time to doing it wrong. That habit has saved me a ***LOT*** of time. OTOH, it has caused some absolutely absurd reactions in some managers. Bob Pendleton P.S. I've also learned that it is damned near impossible to practice egoless programming when you are the only ego on the project.
-- +----------------------------------------------------------- + Bob Pendleton: writer and programmer + email: + web: www.TheGrumpyProgrammer.com |
|||||||||||||||||||||
|
Bug: libsdl not thread-safe |
Paulo Pinto
Guest
|
Very interesting reading.
On Wed, Feb 3, 2010 at 12:19 AM, Bob Pendleton wrote:
|
|||||||||||||||||||||||
|
Bug: libsdl not thread-safe |
Mason Wheeler
Guest
|
From: Bob Pendleton
Subject: Re: [SDL] Bug: libsdl not thread-safe Think about the first time you (not the guy I'm replying to, the everybody version of you) tried to write a game with NPCs in it. I'll just call them actors. The usual first approach to writing an actor leads you to write a loop. Inside the loop you write a whole series of complex, nested, nasty looking if statements. The Ifs test variables in the world and lead to code that changes variables and then to code that draws the actions that result from the decision. Then you go back to the top of the loop and start over. If you pound on that code long enough and hard enough you can make it work. You can make it work for one actor. When you need to handle more than one actor you find that only one actor gets to move at a time because each actor keeps control until it has animated its last decision. You used to see commercial games that showed exactly that kind of behavior. You still see it in a lot of flash games. So what do you do when you find out that your approach can not work? Well, you try to find a way to make it work. The first approach is to jump at threads as a solution. It seems natural to just have a thread per actor so they can all move at once. But, then you find out that doesn't work either because no matter how many threads you have you can only have as many active threads as you have cores (or hyperthreads). So only a few of your actors can move at once. (Threads might also cause you some memory problems if you have a large number of actors.) But, not only don't they move at the same time, but the graphics doesn't work. It doesn't work because the graphics system was *designed* so it would not work. Depending on how clever, and stubborn, you are can keep trying to make it work. But, eventually you run into that last wall. The one that stops you cold. You project does not work and can not work. What do you do know? You have painted yourself into an emotional corner. You have invested a lot of time and effort into something that does not work. In fact, you have invested all that time and effort into something that *can*not* work. It can't work because of the basic design of OpenGL, or X, or DirectX, or whatever you are using. At this point you have a couple of choices. 1) You can accept that maybe the people who designed all that broken stuff knew what they were doing. If you do that you have to admit that you not know as much as they do and also accept that you have to throw all that work away and start over. Or, 2) you can chose to believe that the designers of all that other stuff are complete idiots. You can decide that their entire design was based on stupidity. If you believe all that you can demand that they, or someone else, fix their code. Choice #2 is normal human adolescent male behavior. It is very common human *adult* male behavior. Even women will fall into that behavior pattern at times. Choice #1 is the behavior you hope to see in a seasoned professional who has been schooled in the ways of egoless programming. It is in fact the behavior of Saints and Bodhisattvas, not that of normal human males. (It is a shame that no one teaches egoless programming anymore.) Choice #1 leads to learning about state machines, event driven programming, and an understanding of how to subdivide decisions from actions. It might even lead to an understanding of how to use threads. It is rarely the choice that is made the first time, or even the second time, you run into the impossibility wall. OK, I'm a little confused by this. I needed a game engine that could animate multiple "actors" at the same time. (Of course, I knew that that was a requirement from the beginning, so maybe that helped a little.) I knew I had a framerate, and that actors would need to move at certain speeds, and usually move further than one frame's worth of that speed would allow. So I ended up doing code that worked sort of like this: (Atrocious pseudocode, but you'll get the idea) for each actor in ActorList if not actor.moving then continue deltaVector = actor.destination - actor.position totalDistance = PythagoreanTheorem(deltaVector) movementVector = deltaVector / (totalDistance / actor.MovementSpeed) actor.MoveBy(movementVector) actor.AdvanceAnimation if actor.position = actor.destination then actor.moving = false end for each This approach became obvious after a few minutes of analyzing the requirements. How in the world does someone end up on the path you described that leads to Choice #2? (And what do state machines have to do with it?) |
|||||||||||
|
Bug: libsdl not thread-safe |
Brian Barrett
Guest
|
Do your actors really just go from A to B, then stop? Most real games
want to have some sort of decision making AI, even if it is simple. The state machine approach will support this type of implementation. Though I do agree, I can't see why anyone would jump to threads for actors. It makes sense in a language like Lua where one has lightweight, co-operative "co-routines", but using system threads? I think the essence of Bob's post was correct, though one (as always) can argue about the details. On 3 February 2010 19:58, Mason Wheeler wrote:
SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|
Bug: libsdl not thread-safe |
Mason Wheeler
Guest
|
One of two things. Either they go from A to B then stop, or they go from A to B and then continue on to C. This is handled by a queue of actions which is implemented elsewhere, but moving from B to C is exactly the same as moving from A to B. _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||||
|
Bug: libsdl not thread-safe |
Brian Barrett
Guest
|
Surely its dynamic? Where do the actions in that queue come from? It
is that logic which is often modelled as a state machine - the "AI" part (assuming a bit of autonomy on the actors of course). There is code which needs to make a decision about where to go next (and not necessarily how to get there), this code might need to run frequently to react to a changing environment. A primitive first person shooter enemy - some kind of monster - might start of in the hunting state, where it quickly moves from area to area looking for targets. Once such a target is acquired, it might change state to "combat", where it attempts to kill its opponent. The types of low level actions (such as move from A to B) that will be undertaken are dictated by the overall "state" the monster is in. If your requirements are simpler than that, then fair enough. Bob's example might have assumed a bit about the kind of actors that were being modelled. On 4 February 2010 13:20, Mason Wheeler wrote:
SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
|||||||||||||
|