PCSX2 Documentation/Threading Basics: Difference between revisions

no edit summary
No edit summary
No edit summary
Line 3: Line 3:
In this page are a handful of tips and guidelines for programming with threads. The PCSX2 team provides and updates this resource in large part because there is a lot of mis-information out there when it comes to parallel programming.
In this page are a handful of tips and guidelines for programming with threads. The PCSX2 team provides and updates this resource in large part because there is a lot of mis-information out there when it comes to parallel programming.


InterlockExchange / AtomicExchange
==InterlockExchange / AtomicExchange==
The primary tool of PCSX2 threading is the AtomicExchange method and it's many cousins (see Utilities/Threading.h for all of them). These functions are a friendly C++ layer for underlying _InterlockedExchange intrinsics. Some folks prefer the term Interlocked, but we use Atomic because it's shorter, and begins with 'A' like the A-Team, which is cool.
The primary tool of PCSX2 threading is the AtomicExchange method and it's many cousins (see Utilities/Threading.h for all of them). These functions are a friendly C++ layer for underlying _InterlockedExchange intrinsics. Some folks prefer the term Interlocked, but we use Atomic because it's shorter, and begins with 'A' like the A-Team, which is cool.


In non-debug builds all varieties of Atomic methods translate into one to three inline'd Lock-prefixed instructions. Lock-prefixing is quite efficient on modern CPUs, so there is little concern over using interlocking liberally (better safe than sorry); though they should still only be used as needed in performance-critical code. This guide will help you know exactly when thy are, in fact, needed.
In non-debug builds all varieties of Atomic methods translate into one to three inline'd Lock-prefixed instructions. Lock-prefixing is quite efficient on modern CPUs, so there is little concern over using interlocking liberally (better safe than sorry); though they should still only be used as needed in performance-critical code. This guide will help you know exactly when thy are, in fact, needed.


Atomic Operation Criteria
==Atomic Operation Criteria==
Definition: An atomic operation is one which executes completely, and will not yield a 'partial' result even if a concurrent operation on the same memory address is being performed in parallel. In other words, atomic operations are thread-safe. :)
Definition: An atomic operation is one which executes completely, and will not yield a 'partial' result even if a concurrent operation on the same memory address is being performed in parallel. In other words, atomic operations are thread-safe. :)


Line 17: Line 17:
Translation: If only one thread modifies a variable, no atomic operations are needed. Any number of other threads can safely read that value simutaneously. If more than one thread modifies a variable, all threads must use atomic operations when modifying it!
Translation: If only one thread modifies a variable, no atomic operations are needed. Any number of other threads can safely read that value simutaneously. If more than one thread modifies a variable, all threads must use atomic operations when modifying it!


Mutex and Semaphore
==Mutex and Semaphore==
These are the two most basic tools of the multi-threaded programmer. Understaing their basic functionality and common uses will be important to many programming tasks in PCSX2.
These are the two most basic tools of the multi-threaded programmer. Understaing their basic functionality and common uses will be important to many programming tasks in PCSX2.


Line 28: Line 28:
In PCSX2, it is usually best to use the ScopedLock class instead of acquiring and releasing mutexes directly. This is because PCSX2 uses C++ exceptions just about everywhere, and using a ScopedLock ensures that the mutex will be released if an excepion occurs. Otherwise, a mutex could be left dangling, and some form of deadlock would eventually occur.
In PCSX2, it is usually best to use the ScopedLock class instead of acquiring and releasing mutexes directly. This is because PCSX2 uses C++ exceptions just about everywhere, and using a ScopedLock ensures that the mutex will be released if an excepion occurs. Otherwise, a mutex could be left dangling, and some form of deadlock would eventually occur.


Don't Use Timed Mutexes or Semaphores!
==Don't Use Timed Mutexes or Semaphores!==
Generally speaking, using timeout parameters on mutexes and semaphores is a bad idea. Some people try to use timed mutexes in order to help avoid deadlock scenarios -- this is not recommended. The better alternative is to use Proxy Queue Threads, which allow two complex threads to communicate with eath other safely via a third thread that acts as a proxy.
Generally speaking, using timeout parameters on mutexes and semaphores is a bad idea. Some people try to use timed mutexes in order to help avoid deadlock scenarios -- this is not recommended. The better alternative is to use Proxy Queue Threads, which allow two complex threads to communicate with eath other safely via a third thread that acts as a proxy.


Note that PCSX2 itself does use timed mutexes and semaphores on the Main/UI thread. This feature is indended as a last resort for when bad multithreaded coding practices have resulted in long delays or deadlocks, and should not be relied upon. I may remove them in the future, or replace them with concrete assertion failures.
Note that PCSX2 itself does use timed mutexes and semaphores on the Main/UI thread. This feature is indended as a last resort for when bad multithreaded coding practices have resulted in long delays or deadlocks, and should not be relied upon. I may remove them in the future, or replace them with concrete assertion failures.


Aggressive vs. Passive Threading
==Aggressive vs. Passive Threading==
Aggressive threading uses spins (tight loops) to monitor changes made by other threads.
Aggressive threading uses spins (tight loops) to monitor changes made by other threads.


ninja
782

edits