Concurrent Programming on Windows

by Joe Duffy
ISBN: 0-3214-3482-X
Publisher: Addison Wesley
Pages: 1,008
Availability: November 2008

Free Sample Chapter: Chapter 2: Synchronization and Time
Code Samples: CPOW.zip

Purchase it from: Read about it:

Overview

My aim with this book was to write the book people will buy to understand how to write concurrent programs on the Windows and .NET platforms. This is clearly of increasing importance due to multi-core. This includes a tutorial of the entire set of Windows and .NET APIs required to write concurrent programs. Interspersed among the tutorial are many difficult-to-discover internal details about how things work. Because so much of the threading and synchronization features of the platform are Windows-general, I try to focus on the general behavior first and the API details of native and managed code second.

That are also several practical parallelism algorithms and data structures used for illustration, and best practices and practical topics like debugging and performance. My goal was to treat readers to enough computer-sciency material so that they understand the rich history and evolution of concurrency, but to avoid too much formalism so that professional developers aren’t overwhelmed with theory that isn't directly relevant to actual programming.

I’ve structured the book into four major sections. The first, Concepts, introduces the reader to concurrency at a broad level without going too deep into any one topic. The next section, Mechanisms, focuses squarely on the fundamental platform features, inner workings, and API details. After that, the Algorithms section describes common patterns, best practices, algorithms, and data structures that emerge while writing concurrent software. The fourth and last section, Systems, covers many of the system-wide architectural and process concerns that frequently arise. There is a progression here. Concepts is first because it develops a basic understanding of concurrency in general. Understanding Algorithms would be difficult without a solid understanding of the Mechanisms, and similarly, building real Systems would be impossible without understanding the rest. The reverse is not true at all.

Table of Contents

I. Concepts

1: Introduction

2: Synchronization and Time [PDF Sample Chapter]

II. Mechanisms

3: Threads

4: Advanced Threads

5: Windows Kernel Synchronization

6: Control and Data Synchronization

7: Thread Pools

8: Asynchronous Programming Models

9: Fibers

III. Techniques

10: Memory Models and Lock-Freedom

11: Concurrency Hazards

12: Parallel Containers

13: Data and Task Parallelism

14: Performance and Scalability

IV. Systems

15: Input and Output

16: Graphical User Interfaces

IV. Appendices

A: Designing Reusable Libraries for Concurrent .NET Programs

B: Parallel Extensions to the .NET Framework (Preview)

Errata

Below you will find a compilation of all known errors in the book, organized by printing and sorted by page number complete with the date discovered.

If you find any new errors in the book, I sincerely apologize. I kindly ask that you send them to me at joe AT bluebytesoftware DOT com. I will add them to the list below. Special thanks to Bradley Grainger, Leon Zandman, Klavs Madsen, Dick Baker, Jeff Wolski, Wolfgang Müllauer, Stephen Toub, Slobodan Filipovic, Ma Sebastian, and Ken Kozman for reporting errors already. If you'd prefer that your name be kept private, simply tell me so. Many thanks.

2nd Printing

(December 2008)

ch2, p23, 24, 25, 41: "INC,EAX" => "INC EAX" (replace comma with space)" [11/20/2008]

ch2, p28: "from a location, t2, then writes" => "from a location, t2 then writes" (erroneous comma after t2) [11/20/2008]

ch2, p36: "feature rich-programming" => "feature-rich programming" [11/20/2008]

ch2, p41: "t2(0):" => "t2(E):" [11/20/2008]

ch2, p41: "t2(2): MOV [a],EAX #3" => "t2(2): MOV [a],EAX #2" [1/3/2009]

ch2, p43: "static int a;" => "static int s_a;" [1/31/2009]

ch2, p46: "organized as a collection subsystems" => "organized as a collection of subsystems" [11/20/2008]

ch2, p60: "will have to take on such a thread" => "will have to take on such a task" [11/20/2008]

ch2, p60: "primitives are not up to the thread" => "primitives are not up to the task" [11/20/2008]

ch2, p62: "to perform this activity' or (3)" => "to perform this activity or (3)" [11/20/2008]

ch3, p83: Missing comma: "used to begin a thread's life an unhandled exception, or" => "used to begin a thread's life, an unhandled exception, or" [12/18/2008]

ch3, p88: "from thread management minutia and back" => "from thread management minutiae and back" [1/4/2009]

ch3, p106: "after finallys blocks have been run." => "after finally blocks have been run." [11/20/2008]

ch3, p108: "calls ExitThread (via_end_threadex) at the base" => "calls ExitThread (via _end_threadex) at the base" (need a space between via and _end) [2/9/2009]

ch3, p108: "thread's stack is not before exiting." => "thread's stack is not unwound before exiting." [11/20/2008]

ch3, p116: "The DllMain function is one of few places" => "The DllMain function is one of the few places" [2/9/2009]

ch3, p122: "are unnecessary because data store in TLS variables" => "are unnecessary because data stored in TLS variables" [2/9/2009]

ch3, p122: "some circumstances in which you may need more dynamic in the way" => "some circumstances in which you may need to be more dynamic in the way" [2/10/2009]

ch4, p130 "We'll begin with brief overview" => "We'll begin with a brief overview" [2/10/2009]

ch4, p132: "/STACK:reserveBytes,[commitBytes]" => "/STACK:reserveBytes[,commitBytes]" (comma should be in square brackets) [11/20/2008]

ch4, p153: "from the GetUserContext Win32" => "from the GetThreadContext Win32" [11/20/2008]

ch4, p156: "memory need for to run has" => "memory needed to run has" [1/3/2009]

ch4, p157: "requiring memorizing these values." => "requiring memorization of these values." [1/3/2009]

ch4, p159: "understand them. It's particularly important to understand them, because only then" => "understand them. Only then" [1/3/2009]

ch4, p161: ", 15 for dynamic range" => ", 16 for dynamic range" (in Table 4.2) [1/3/2009]

ch4, p162: "By default, all I/O under" => "By default, all I/O runs under" [1/3/2009]

ch5, p185: Mysterious "it:": “it can easily wait on with a Win32 or .NET wait API: it: if the” => “it can easily wait on it with a Win32 or .NET wait API: if the” [11/8/2008]

ch5, p192: "let t2's wait on a succeed" => "let t2's wait on A succeed" [1/3/2009]

ch5, p192: ", FALSE, INFINITE);" => ", FALSE, 1000);" (the WAIT_TIMEOUT case shown wouldn't be exercised otherwise) [1/3/2009]

ch5, p199: "MsgWaitForMultipleObjectsExwill process" => "MsgWaitForMultipleObjectsEx will process" (space between function name and will, and wrong typeface for will) [1/3/2009]

ch5, p211: "transition, while the other will see" => "transition, while the others will see" [1/3/2009]

ch5, p225: "dominate you're resulting" => "dominate your resulting" [11/20/2008]

ch5, p232: "holds on to resource that" => "holds on to a resource that" [11/20/2008]

ch5, p235: "in the dwFlags argu-ment; its" => "in the dwFlags argument; its" [11/20/2008]

ch5, p236: "The pDueTimer and lPeriod arguments" => "The pDueTime and lPeriod arguments [12/29/2008]

ch5, p240: "two's compliment" => "two's complement" [11/20/2008]

ch5, p241: "initializes the FILETIME's fields" => "initializes the FILETIME's fields:" (should end in colon)" [11/20/2008]

ch5, p243: "SignalObjectAndWait Win 32 function" => "SignalObjectAndWait Win32 function" (should be no space between Win and 32)" [11/20/2008]

ch5, p245 249: "// If the queue is empty, we will need exit the" => "// If the queue is empty, we will need to exit the" [2/12/2009]

ch5, p248: "// in a signaled set, possibly waking waiters." => "// in a signaled state, possibly waking waiters." [2/12/2009]

ch6, p265: "always ignored on single-threaded machines." => "always ignored on single-processor machines." [1/8/2009]

ch6, p268: "they used by EnterCriticalSection" => "they are used by EnterCriticalSection" [1/8/2009]

ch6, p292: "due a big scope." => "due to a big scope."Bradley Grainger11/20/2008]

ch7, p347: "DisassosiateCurrentThreadFromCallback" => "DisassociateCurrentThreadFromCallback" [11/20/2008]

ch7, p349: "tying up one of the thread pools." => "tying up one of the thread pool's." [11/20/2008]

ch7, p377: "You should not to rely on these" => "You should not rely on these" [1/6/2009]

ch8, p414: "private SimpleAsyncResult(" => "public SimpleAsyncResult(" [2/9/2009]

ch8, p415: "// Runs the thread on the thread pool" => "// Runs the work on the thread pool"[2/9/2009]

ch8, p415: "if (!m_isCompleted)" => "if (m_isCompleted == 0)"[2/9/2009]

ch10, p489: "MOV EAX,[s_x+4]" => "MOV EDX,[s_x+4]" [11/20/2008]

ch10, p494: "private volatile int m_taken = 0;" => "private volatile int m_taken;" [2/9/2009]

ch10, p497: "private volatile int m_taken = 0;" => "private volatile int m_taken;" [2/9/2009]

ch10, p498: "location, value, comparand) == comparand;" => "ref location, value, comparand) == comparand;" [2/9/2009]

ch10, p502: "writing code in C++ and)" => "writing code in C++)" [11/20/2008]

ch10, p505: "newValue = func(value);" => "newValue = func(oldValue);" [2/9/2009]

ch10, p505: "InterlockedUpdate(location, (x) => x ^ xorValue);" => "InterlockedUpdate(ref location, (x) => x ^ xorValue)" [2/9/2009]

ch10, p506: "ING" => "LOCK INC" (in Figure 10.2's labels)" [11/20/2008]

ch10, p526: "Get" => "get" (in the code sample for LazyInitRelaxedRef<T>)" [2/12/2009]

ch10, p527: "return m_value;" => "return m_value.m_value;" (in the code sample for LazyInitRelaxedVal<T>)" [2/12/2009]

ch11, p553: "return currentHead.m_value;" should be inside the "lock { .. }" block, because currentHead is out of scope otherwise." [11/20/2008]

ch11, p610: "lead to three of the affected patents dying" => "led to three of the affected patients dying" [1/24/2009]

ch12, p628: "level == # procs" => "level == # procs X 8" and "this(Environment.ProcessorCount) { }" => "this(Environment.ProcessorCount * 8) { }" (in the FineGrainedHashtable sample; sizing lock table equal to # processors leads to unusually frequent false conflicts) [2/12/2009]

ch12, p629: "returning false not found." => "returning false if not found." (in the FineGrainedHashtable sample) [2/12/2009]

ch12, p632: "public ConcurrentQueue()" => "public LockFreeQueue()" [11/20/2008]

ch12, p643: "// Queue is empty, wait until en element arrives." => "// Queue is empty, wait until an element arrives." [2/12/2009]

ch12, p651: "internal void SignalAndWait()" => "public void SignalAndWait()" and "internal bool TrySignalAndWait(" => "public bool TrySignalAndWait(" [2/12/2009]

ch13, p691: TryRun's return type should be "bool" (not "void"), and there are missing return statements: [1/29/2009]

        private bool TryRun()
        {
            if (m_state == 0 &&
                Interlocked.CompareExchange(ref m_state, 1, 0) == 0)
            {
                try
                {
                    m_value = m_func();
                }
                catch (Exception e)
                {
                    m_exception = e;
                }
                finally
                {
                    m_state = 2;
                    m_event.Set();
                }
                return true;
            }
            return false;
        }

[11/29/2008]

index, p947: "deciding to go parallel" has some strange i characters in it [1/11/2009]

1st Printing

(October 2008)

ch1, p9: “Figure 1.2. A taxonomy of concurrent program structure” => “Figure 1.2. The concurrency landscape as three concentric circles” [11/8/2008, Fixed in 2nd Printing]

ch2, p18: “C c2 = new C()” => “C * c2 = new C()” and also references using “.” must use “->” [11/8/2008, Fixed in 2nd Printing]

ch2, p23, 24, 25, 41: "INC,EAX" => "INC EAX" (replace comma with space)" [11/20/2008]

ch2, p28: "from a location, t2, then writes" => "from a location, t2 then writes" (erroneous comma after t2) [11/20/2008]

ch2, p36: "feature rich-programming" => "feature-rich programming" [11/20/2008]

ch2, p41: "t2(0):" => "t2(E):" [11/20/2008]

ch2, p41: "t2(2): MOV [a],EAX #3" => "t2(2): MOV [a],EAX #2" [1/3/2009]

ch2, p43: "static int a;" => "static int s_a;" [1/31/2009]

ch2, p46: "organized as a collection subsystems" => "organized as a collection of subsystems" [11/20/2008]

ch2, p60: "will have to take on such a thread" => "will have to take on such a task" [11/20/2008]

ch2, p60: "primitives are not up to the thread" => "primitives are not up to the task" [11/20/2008]

ch2, p62: "to perform this activity' or (3)" => "to perform this activity or (3)" [11/20/2008]

ch3, p79: “parts of the program running inside a single program at once.” => “parts of the program running inside a single process at once.” [11/8/2008, Fixed in 2nd Printing]

ch3, p83: Missing comma: "used to begin a thread's life an unhandled exception, or" => "used to begin a thread's life, an unhandled exception, or" [12/18/2008]

ch3, p87: Phase repeated: “We will also discuss We will also discuss a” => “We will also discuss a” [11/8/2008, Fixed in 2nd Printing]

ch3, p88: "from thread management minutia and back" => "from thread management minutiae and back" [1/4/2009]

ch3, p106: "after finallys blocks have been run." => "after finally blocks have been run." [11/20/2008]

ch3, p108: "calls ExitThread (via_end_threadex) at the base" => "calls ExitThread (via _end_threadex) at the base" (need a space between via and _end) [2/9/2009]

ch3, p108: "thread's stack is not before exiting." => "thread's stack is not unwound before exiting." [11/20/2008]

ch3, p116: "The DllMain function is one of few places" => "The DllMain function is one of the few places" [2/9/2009]

ch3, p122: "are unnecessary because data store in TLS variables" => "are unnecessary because data stored in TLS variables" [2/9/2009]

ch3, p122: "some circumstances in which you may need more dynamic in the way" => "some circumstances in which you may need to be more dynamic in the way" [2/10/2009]

ch4, p129 “at an address less than the function” => “at an address higher than the function” [11/8/2008, Fixed in 2nd Printing]

ch4, p130 "We'll begin with brief overview" => "We'll begin with a brief overview" [2/10/2009]

ch4, p132: "/STACK:reserveBytes,[commitBytes]" => "/STACK:reserveBytes[,commitBytes]" (comma should be in square brackets) [11/20/2008]

ch4, p153: "from the GetUserContext Win32" => "from the GetThreadContext Win32" [11/20/2008]

ch4, p156: "memory need for to run has" => "memory needed to run has" [1/3/2009]

ch4, p157: "requiring memorizing these values." => "requiring memorization of these values." [1/3/2009]

ch4, p159: "understand them. It's particularly important to understand them, because only then" => "understand them. Only then" [1/3/2009]

ch4, p161: ", 15 for dynamic range" => ", 16 for dynamic range" (in Table 4.2) [1/3/2009]

ch4, p162: "By default, all I/O under" => "By default, all I/O runs under" [1/3/2009]

ch5, p185: Mysterious "it:": “it can easily wait on with a Win32 or .NET wait API: it: if the” => “it can easily wait on it with a Win32 or .NET wait API: if the” [11/8/2008]

ch5, p192: "let t2's wait on a succeed" => "let t2's wait on A succeed" [1/3/2009]

ch5, p192: ", FALSE, INFINITE);" => ", FALSE, 1000);" (the WAIT_TIMEOUT case shown wouldn't be exercised otherwise) [1/3/2009]

ch5, p199: "MsgWaitForMultipleObjectsExwill process" => "MsgWaitForMultipleObjectsEx will process" (space between function name and will, and wrong typeface for will) [1/3/2009]

ch5, p211: "transition, while the other will see" => "transition, while the others will see" [1/3/2009]

ch5, p225: "dominate you're resulting" => "dominate your resulting" [11/20/2008]

ch5, p232: "holds on to resource that" => "holds on to a resource that" [11/20/2008]

ch5, p235: "in the dwFlags argu-ment; its" => "in the dwFlags argument; its" [11/20/2008]

ch5, p236: "The pDueTimer and lPeriod arguments" => "The pDueTime and lPeriod arguments [12/29/2008]

ch5, p240: "two's compliment" => "two's complement" [11/20/2008]

ch5, p241: "initializes the FILETIME's fields" => "initializes the FILETIME's fields:" (should end in colon)" [11/20/2008]

ch5, p243: "SignalObjectAndWait Win 32 function" => "SignalObjectAndWait Win32 function" (should be no space between Win and 32)" [11/20/2008]

ch5, p245, 249: "// If the queue is empty, we will need exit the" => "// If the queue is empty, we will need to exit the" [2/12/2009]

ch5, p248: "// in a signaled set, possibly waking waiters." => "// in a signaled state, possibly waking waiters." [2/12/2009]

ch6, p265: "always ignored on single-threaded machines." => "always ignored on single-processor machines." [1/8/2009]

ch6, p268: "they used by EnterCriticalSection" => "they are used by EnterCriticalSection" [1/8/2009]

ch6, p292: "due a big scope." => "due to a big scope."Bradley Grainger11/20/2008]

ch7, p347: "DisassosiateCurrentThreadFromCallback" => "DisassociateCurrentThreadFromCallback" [11/20/2008]

ch7, p349: "tying up one of the thread pools." => "tying up one of the thread pool's." [11/20/2008]

ch7, p377: "You should not to rely on these" => "You should not rely on these" [1/6/2009]

ch8, p414: "private SimpleAsyncResult(" => "public SimpleAsyncResult(" [2/9/2009]

ch8, p415: "// Runs the thread on the thread pool" => "// Runs the work on the thread pool"[2/9/2009]

ch8, p415: "if (!m_isCompleted)" => "if (m_isCompleted == 0)"[2/9/2009]

ch10, p489: "MOV EAX,[s_x+4]" => "MOV EDX,[s_x+4]" [11/20/2008]

ch10, p494: "private volatile int m_taken = 0;" => "private volatile int m_taken;" [2/9/2009]

ch10, p497: "private volatile int m_taken = 0;" => "private volatile int m_taken;" [2/9/2009]

ch10, p498: "location, value, comparand) == comparand;" => "ref location, value, comparand) == comparand;" [2/9/2009]

ch10, p502: "writing code in C++ and)" => "writing code in C++)" [11/20/2008]

ch10, p505: "newValue = func(value);" => "newValue = func(oldValue);" [2/9/2009]

ch10, p505: "InterlockedUpdate(location, (x) => x ^ xorValue);" => "InterlockedUpdate(ref location, (x) => x ^ xorValue)" [2/9/2009]

ch10, p506: "ING" => "LOCK INC" (in Figure 10.2's labels)" [11/20/2008]

ch10, p526: "Get" => "get" (in the code sample for LazyInitRelaxedRef<T>)" [2/12/2009]

ch10, p527: "return m_value;" => "return m_value.m_value;" (in the code sample for LazyInitRelaxedVal<T>)" [2/12/2009]

ch11, p553: "return currentHead.m_value;" should be inside the "lock { .. }" block, because currentHead is out of scope otherwise." [11/20/2008]

ch11, p610: "lead to three of the affected patents dying" => "led to three of the affected patients dying" [1/24/2009]

ch12, p628: "level == # procs" => "level == # procs X 8" and "this(Environment.ProcessorCount) { }" => "this(Environment.ProcessorCount * 8) { }" (in the FineGrainedHashtable sample; sizing lock table equal to # processors leads to unusually frequent false conflicts) [2/12/2009]

ch12, p629: "returning false not found." => "returning false if not found." (in the FineGrainedHashtable sample) [2/12/2009]

ch12, p632: "public ConcurrentQueue()" => "public LockFreeQueue()" [11/20/2008]

ch12, p643: "// Queue is empty, wait until en element arrives." => "// Queue is empty, wait until an element arrives." [2/12/2009]

ch12, p651: "internal void SignalAndWait()" => "public void SignalAndWait()" and "internal bool TrySignalAndWait(" => "public bool TrySignalAndWait(" [2/12/2009]

ch13, p691: TryRun's return type should be "bool" (not "void"), and there are missing return statements: [1/29/2009]

        private bool TryRun()
        {
            if (m_state == 0 &&
                Interlocked.CompareExchange(ref m_state, 1, 0) == 0)
            {
                try
                {
                    m_value = m_func();
                }
                catch (Exception e)
                {
                    m_exception = e;
                }
                finally
                {
                    m_state = 2;
                    m_event.Set();
                }
                return true;
            }
            return false;
        }

[11/29/2008]

index, p947: "deciding to go parallel" has some strange i characters in it [1/11/2009]

Source Code for Examples

Download CPOW.zip. Please do not hesitate to email if you have any questions.




© Joe Duffy, 2007-2008
joe AT bluebytesoftware DOT com