Author: Scott Gasch
Date: 14:12:45 12/27/01
Go up one level in this thread
Darnit, I was typing code and hit "tab (oops) space" and submitted before I was
done.. here's the full message:
>On December 27, 2001 at 14:25:09, Russell Reagan wrote:
>
>...
>>In other words, I could implement a
>>multithreaded application using critical sections, and I could do it using
>>mutexes, and the other methods, but I don't know if I'm done after I get my
>>program working with only one of those schemes.
>>
>>Are critical sections used for a certain problem, and mutexes used for another,
>>and semaphores used for yet another? Or are they all an attempted solution to
>>the same problem? And do I need to use more than one of these in my program, or
>>will one of these methods solve the problem? And if one will do, are there any
>>that would serve a chess program better than the others?
>
All of these things (and more!) are mutual exclusion devices. From your reading
I'm sure you understand that they are used to acquire a lock and prevent other
threads of execution from accessing some public resource.
One of the cheapest ways to accomplish this is with interlocked operations. If
you are developing under win32, look at InterlockedIncrement,
InterlockedCompareExchange, etc. These are very fast and will accomplish mutual
exclusion within one process (among threads).
Critical sections (I'm talking win32 CRITICAL_SECTIONs here) are another way to
do mutual exclusion within one process. The difference between a critical
section and interlocked operations is that a critical section is more expensive
and allows a blocking wait. With interlocked stuff you have to spin in a loop
trying to get the lock. If the lock is already possessed by another thread, the
thread trying to acquire it will spin in this loop until the lock is released.
This, of course, burns cycles. It's a good idea to keep the size of the
critical code (between getting the lock and releasing it) minimal always but
especially when using interlocked operations.
lStartVal = UNLOCKED_VALUE;
lNewValue = LOCKED_VALUE;
while(InterlockedCompareExchange(&lLock,
lNewValue,
lStartValue) != lStartValue)
{
// do nothing (or maybe Sleep(0) to give up quantum
}
// we have the lock
With critical sections there's a blocking call so that the waiting thread
doesn't have to spin. EnterCriticalSection suspends the waiting thread until
the lock is available. The OS will not reschedule it until the lock is released
by whoever owns it. If more than one thread is waiting on the lock when its
released, they are woken up and given the lock in FIFO order (although this may
change in the future). You can implement a critical section spin lock with the
non-blocking TryEntryCriticalSection call, too.
EnterCriticalSection(&cs); // this blocks until it has the lock
// we have the lock
or the spinning version...
while (FALSE == TryEnterCriticalSection(&cs))
{
// do nothing, or maybe Sleep(0);
}
You can also tell the critical section code that you want EnterCriticalSection
to spin a few times (in a loop) trying to get the lock before giving up and
suspending your thread until the lock is available. You do this at the creation
time of the critical section.
Semaphores and mutexes are even more expensive than critical sections ... and
way more expensive than interlocked stuff. They create kernel objects that can
be used to synchronize code across processes. There's no need for something
this expensive in a chess engine, usually.
Scott
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.