Thread: RE: [GD-Windows] TryEnterCriticalSection
Brought to you by:
vexxed72
From: Andy G. <an...@mi...> - 2002-01-03 19:41:43
|
There is a good performance comparison of different sync objects found at=20 http://www.usenix.org/publications/library/proceedings/usenix-nt98/full_ papers/zabatta/zabatta_html/zabatta.html It depends upon what you are trying to do and how often you will check/set/block in your code. Personally I would write my own sync object using _asm lock cmpxchg - then it would run on all CPUs 486 and above... There are very neat sync objects in the later OS's - SLIST for example is very clever, but only in XP and above (of course, you could implement it yourself without too much trouble) - also spin locks may be useful if you only lock the resource very briefly. Andy Glaister. -----Original Message----- From: Brian Hook [mailto:bri...@py...]=20 Sent: Thursday, January 03, 2002 11:18 AM To: gam...@li... Subject: [GD-Windows] TryEnterCriticalSection It looks like TryEnterCriticalSection is only available on >=3D NT4 (and according to the docs, it's not available on Win9x at all). To get around this I'm thinking that I could switch to using a mutex and WaitForSingleObject with a timeout of 0 milliseconds, but mutexes are heavier weight than critical sections (I'm not sure how bad this is in practice though). Any opinions, comments or shared experiences with this? Brian _______________________________________________ Gamedevlists-windows mailing list Gam...@li... https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows |
From: Brian S. <bs...@mi...> - 2002-01-03 20:20:47
|
There's also all the Interlocked* functions, like InterlockedCompareExchange, for those who have a hard time remembering x86 asm instructions. And for those, like myself, who never knew the instructions :). =20 I've used mutexes (mutices?) a lot, for instance when walking common data structures like network message queues (receive messages on worker thread, process messages on main thread). My usage has typically been with 2 threads going. I've never sensed a problem. I don't know what the internal implementation is like, but I would guess that lots of time has been spent making sync primitives as efficient as possible. =20 If you're worried about the cost of wait objects vs. critical sections, then I guess one question you could ask yourself is, does the time required for WaitForSingleObject(0) compare at all to the time that your thread would just sit there if you just used EnterCritSection instead of TryEnterCritSection? How long do the threads typically hold the critical section? Is your goal to actually avoid having multiple threads execute through the guarded section in close temporal sequence, or are you just worried about having other threads waiting idle while one thread goes through it? Maybe more details about how many threads you have going, what they're doing, how many different places the critical section is currently being used, etc. would help get answers that are more useful to you. --brian -----Original Message----- From: Andy Glaister [mailto:an...@mi...]=20 Sent: Thursday, January 03, 2002 11:42 AM To: gam...@li... Subject: RE: [GD-Windows] TryEnterCriticalSection There is a good performance comparison of different sync objects found at=20 http://www.usenix.org/publications/library/proceedings/usenix-nt98/full_ papers/zabatta/zabatta_html/zabatta.html It depends upon what you are trying to do and how often you will check/set/block in your code. Personally I would write my own sync object using _asm lock cmpxchg - then it would run on all CPUs 486 and above... There are very neat sync objects in the later OS's - SLIST for example is very clever, but only in XP and above (of course, you could implement it yourself without too much trouble) - also spin locks may be useful if you only lock the resource very briefly. Andy Glaister. -----Original Message----- From: Brian Hook [mailto:bri...@py...]=20 Sent: Thursday, January 03, 2002 11:18 AM To: gam...@li... Subject: [GD-Windows] TryEnterCriticalSection It looks like TryEnterCriticalSection is only available on >=3D NT4 (and according to the docs, it's not available on Win9x at all). To get around this I'm thinking that I could switch to using a mutex and WaitForSingleObject with a timeout of 0 milliseconds, but mutexes are heavier weight than critical sections (I'm not sure how bad this is in practice though). Any opinions, comments or shared experiences with this? Brian _______________________________________________ Gamedevlists-windows mailing list Gam...@li... https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows _______________________________________________ Gamedevlists-windows mailing list Gam...@li... https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows |
From: Brian H. <bri...@py...> - 2002-01-03 20:40:14
|
> I've used mutexes (mutices?) a lot, for instance when walking > common data structures like network message queues (receive > messages on worker thread, process messages on main thread). That's pretty much exactly what I'm going to be using them for. I need to have synchronized access to my event queue, which may be written to by an external network thread. I don't NEED TryEnterCriticalSection at this point, but I'm trying to make sure that I leave that option open later. Right now I have my HMutex and HCriticalSection class, but the latter can really just be removed if I switch to mutices exclusively (not pun intended). Then again, the HCriticalSection class is all of 30 lines of code, so keeping it around wouldn't hurt. > Maybe more details about how many threads you have going, > what they're doing, how many different places the critical > section is currently being used, etc. would help get answers > that are more useful to you. At this point I'm just trying to get a semblance of a general synchronization architecture in place that can be used for a bunch of different things. The only two concrete areas I have, however, are an audio thread and a network pump. The audio thread presumably needs synchronized access to my direct sound object and buffers, but a hard wait is fine. Same goes with the network pump feeding an event queue -- it's not going to hold a lock for a very long time by any means. -Brian |
From: Brian S. <bs...@mi...> - 2002-01-04 21:00:26
|
I'm not sure that "snooze and re-try" is much better than calling a wait function (EnterCriticalSection, WaitForxxxx, etc.) that triggers a context switch, for a few reasons. If you're just going to spin and wait, then you've got a thread doing nothing while other threads could be working. If you call Sleep, you give up the rest of your timeslice and trigger a context switch anyway. The scheduler can trigger context switches at any time - it doesn't need to wait for you to call Sleep - so it's not like you can prevent that, unless you stop using threads and switch to a polling model. Finally, if the network thread is using a wait function on a socket to block until data arrives, it won't even be considered for scheduling, so that improves your chances of not entering a race with the main thread. =20 It seems to me that the best approach is use OS locks and minimize the time locks are held. Am I missing something here? --brian -----Original Message----- From: Jon Watte [mailto:hp...@mi...]=20 Sent: Thursday, January 03, 2002 4:15 PM To: Gamedevlists-Windows@Lists. Sourceforge. Net Subject: RE: [GD-Windows] TryEnterCriticalSection In my experience, when you find you want to "try to grab a lock if=20 possible," you are most often better off re-designing your algorithm=20 to not use that. More often than not, there's a race waiting to happen=20 that you don't realize if you find you need this. And, for low-latency applications (like games), I've found that you're=20 much better off using non-blocking primitives than trying to go through=20 context switches -- they add up pretty quickly! A non-blocking* FIFO is=20 quite simple to implement using an atomic add-and-return-old-value=20 function, if you only ever have one reader and one writer, for example. For your event queue, you could just have a sufficiently large list of=20 events waiting to be inserted implemented as a non-blocking FIFO, and=20 have the "poll for next event" function empty out whatever's there when=20 the function gets entered and put it into the queue. Cheers, / h+ * Non-blocking primitives force you to decide what to do if the "put"=20 operation fails because there's not enough space, though -- snooze and=20 re-try is often good enough; the idea is that you allocate a sufficient=20 buffer area up-front that you seldom get into that case, and when you=20 do, snoozing is the right thing to do because the other guy's falling=20 behind too much. If you're using a non-reliable mechanism like UDP, you=20 may decide to start dropping packets instead. > -----Original Message----- > From: gam...@li... > [mailto:gam...@li...]On Behalf Of > Brian Hook > Sent: Thursday, January 03, 2002 11:18 AM > To: gam...@li... > Subject: [GD-Windows] TryEnterCriticalSection >=20 >=20 > It looks like TryEnterCriticalSection is only available on >=3D NT4 = (and > according to the docs, it's not available on Win9x at all). To get > around this I'm thinking that I could switch to using a mutex and > WaitForSingleObject with a timeout of 0 milliseconds, but mutexes are > heavier weight than critical sections (I'm not sure how bad this is in > practice though). >=20 > Any opinions, comments or shared experiences with this? >=20 > Brian >=20 >=20 > _______________________________________________ > Gamedevlists-windows mailing list > Gam...@li... > https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows >=20 _______________________________________________ Gamedevlists-windows mailing list Gam...@li... https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows |
From: Jon W. <hp...@mi...> - 2002-01-04 21:56:53
|
> It seems to me that the best approach is use OS locks and minimize the > time locks are held. Am I missing something here? The non-blocking FIFO is supposed to be sized big enough that "normal" operating conditions always leaves free space in it. Thus, the normal case is to pay no additional cost except the memory bus atomic instruction cost, which is small for most architectures (compared to entering the kernel -- ouch!) You can get some of the same benefits by wrapping your blocking kernel primitive in an atomic memory primitive, and only call into the kernel when you actually need to block; assuming low contention this is a win. When we did BeOS, we called this pattern a "benaphore"; you might turn up something with a web search on that term. Cheers, / h+ |
From: Brian S. <bs...@mi...> - 2002-01-07 18:36:12
|
Thought this might be interesting: http://www.cs.rochester.edu/u/michael/PODC96.html Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms Abstract Drawing ideas from previous authors, we present a new non-blocking concurrent queue algorithm and a new two-lock queue algorithm in which one enqueue and one dequeue can proceed concurrently. Both algorithms are simple, fast, and practical; we were surprised not to find them in the literature. Experiments on a 12-node SGI Challenge multiprocessor indicate that the new non-blocking queue consistently outperforms the best known alternatives; it is the clear algorithm of choice for machines that provide a universal atomic primitive (e.g. compare-and-swap or load-linked/store-conditional). The two-lock concurrent queue outperforms a single lock when several processes are competing simultaneously for access; it appears to be the algorithm of choice for busy queues on machines with non-universal atomic primitives (e.g. test-and-set). Since much of the motivation for non-blocking algorithms is rooted in their immunity to large, unpredictable delays in process execution, we report experimental results both for systems with dedicated processors and for systems with several processes multiprogrammed on each processor. --brian -----Original Message----- From: Brian Hook [mailto:bri...@py...]=20 Sent: Thursday, January 03, 2002 11:18 AM To: gam...@li... Subject: [GD-Windows] TryEnterCriticalSection It looks like TryEnterCriticalSection is only available on >=3D NT4 (and according to the docs, it's not available on Win9x at all). To get around this I'm thinking that I could switch to using a mutex and WaitForSingleObject with a timeout of 0 milliseconds, but mutexes are heavier weight than critical sections (I'm not sure how bad this is in practice though). Any opinions, comments or shared experiences with this? Brian _______________________________________________ Gamedevlists-windows mailing list Gam...@li... https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows |