Programming with Concurrency #1: Concepts, Patterns, and Best Practices Jan Gray FUN302 Software...
-
Upload
oscar-clark -
Category
Documents
-
view
245 -
download
0
Transcript of Programming with Concurrency #1: Concepts, Patterns, and Best Practices Jan Gray FUN302 Software...
Programming with Concurrency Programming with Concurrency #1: Concepts, Patterns, and Best #1: Concepts, Patterns, and Best PracticesPractices
Jan GrayJan GrayFUN302FUN302Software ArchitectSoftware ArchitectMicrosoft CorporationMicrosoft Corporation
OutlineOutline
Why concurrency?Why concurrency?
Concurrency programming todayConcurrency programming today
Future concurrency modelsFuture concurrency models
Why Concurrency?Why Concurrency?
For responsiveness: don’t lock up!For responsiveness: don’t lock up!
For performance: parallelismFor performance: parallelism
Situation inducedSituation induced
Why Why notnot concurrency? concurrency?It brings non-determinismIt brings non-determinism
Specific knowledge and discipline Specific knowledge and discipline neededneeded
Concurrency for Concurrency for ResponsivenessResponsiveness
““All apps are network apps”All apps are network apps”Use web services, network files, slow disks, Use web services, network files, slow disks, ……
Latency, variance, timeouts, partial failureLatency, variance, timeouts, partial failure
How are we doing?How are we doing?User is locked out, can’t cancel, no User is locked out, can’t cancel, no repaintingrepainting
Hangs as prevalent and disruptive as Hangs as prevalent and disruptive as crashescrashes
Towards a Responsive AppTowards a Responsive AppDecouple UI and workDecouple UI and work
Show internal states and partial resultsShow internal states and partial results
Provide ‘cancel’Provide ‘cancel’
Exploit pre- and post-computingExploit pre- and post-computing
Define async states and behaviorsDefine async states and behaviorsSo each is a feature, not a bugSo each is a feature, not a bug
Apply same ideas to responsive Apply same ideas to responsive librarieslibraries
Document thread safe synchronous usageDocument thread safe synchronous usage
Watch out for thread issues in libraries you Watch out for thread issues in libraries you callcall
Building a Responsive UI Building a Responsive UI With BackgroundWorkerWith BackgroundWorker
Threads, UI, Thread PoolThreads, UI, Thread Pool
UI ThreadUI Thread
UI Message QueueUI Message Queue(and Pumping)(and Pumping)
Thread PoolThread Pool
Thread PoolThread PoolThreadThread
RunWorkerAsyncRunWorkerAsync
ProgressChangedProgressChanged
RunWorkerCompletedRunWorkerCompleted
DoW
ork
DoW
ork
Concurrency for Concurrency for PerformancePerformanceWelcome to the multi-core era!Welcome to the multi-core era!
Processors don’t get way faster –Processors don’t get way faster –You just get more and more slow You just get more and more slow onesones
log transistors/dielog transistors/dielog CPU clock freqlog CPU clock freq
2003200319751975
10,00010,0001 MHz1 MHz
100 M100 M3 GHz3 GHz
20152015
5 B5 B
<10 GHz<10 GHz
<10%/y<10%/y
>30%/y>30%/y
!!
20052005→2010 →2010 Microprocessor Microprocessor TrendsTrends90→65→45 nm lithography advances90→65→45 nm lithography advances
Twice, twice again as many (faster) Twice, twice again as many (faster) transistorstransistors““Slower” wires + maxed out thermal Slower” wires + maxed out thermal envelopeenvelope→ slower CPU frequency scaling→ slower CPU frequency scalingSame freq + more cores + more cache Same freq + more cores + more cache RAMRAM→ ~same cache/core and compute/core→ ~same cache/core and compute/core
Architecture advancesArchitecture advances(Hardware) multithreading(Hardware) multithreadingOptimizing for throughput, powerOptimizing for throughput, powerSystem-on-a-Chip integration: System-on-a-Chip integration: interconnects, shared caches, I/O and interconnects, shared caches, I/O and DRAM controllersDRAM controllers
Proliferation of PC multiprocessor Proliferation of PC multiprocessor topologiestopologies
Change and OpportunityChange and OpportunityWindows Vista era: 1-4 cores, 1-8 hw Windows Vista era: 1-4 cores, 1-8 hw threads?threads?
Soon cheap servers with Soon cheap servers with many many corescores
Great opportunities for new killer appsGreat opportunities for new killer apps
Chip vendors can and will provide as Chip vendors can and will provide as many cores and threads as developers many cores and threads as developers can harnesscan harness
If you come, they will build itIf you come, they will build it
Concurrency for Concurrency for Performance?Performance?Many of today’s apps are not CPU Many of today’s apps are not CPU
boundboundGreater use of concurrency for Greater use of concurrency for responsivenessresponsiveness enables increased CPU enables increased CPU utilizationutilization
IfIf CPU bound, consider parallelism CPU bound, consider parallelismTune your algorithms and dataTune your algorithms and data first!first!
Let perf goals and measurements guide Let perf goals and measurements guide youyouEvery ~2 years, twice as many cores...Every ~2 years, twice as many cores...(See also)(See also)
Improving .NET App. Perf. and ScalabilityImproving .NET App. Perf. and Scalability::http://msdn.microsoft.com/library/en-ushttp://msdn.microsoft.com/library/en-us /dnpag/html/ /dnpag/html/scalenetscalenet.asp.aspRico Mariani’s blogRico Mariani’s blog: : http://blogs.msdn.com/http://blogs.msdn.com/ricomricom
OutlineOutline
Why concurrency?Why concurrency?
Concurrency programming todayConcurrency programming today
Future concurrency modelsFuture concurrency models
Some Concurrency Some Concurrency Programming ModelsProgramming Models
Server per-client work-unit Server per-client work-unit parallelismparallelismImplicit data parallelism: SQL, Implicit data parallelism: SQL, Direct3DDirect3DInduced concurrency: UI events, CLR Induced concurrency: UI events, CLR finalizers, web servicesfinalizers, web servicesLoop parallelism: OpenMPLoop parallelism: OpenMPMessage passing: MPI, CMessage passing: MPI, Cωω, CCR, CCRImplicit parallelism in functional Implicit parallelism in functional languageslanguagesThreads, shared memory, and Threads, shared memory, and lockslocks
Threads, Shared Memory, Threads, Shared Memory, and Locks: Concepts (1 of 2)and Locks: Concepts (1 of 2)
““Simultaneous” multiple threads of Simultaneous” multiple threads of controlcontrol
Shared memory changes under youShared memory changes under youShared: global data, static fields, heap Shared: global data, static fields, heap objects objects
Private: PC, registers, locals, stack, Private: PC, registers, locals, stack, unshared heap objects, thread local unshared heap objects, thread local storagestorage
The three isolation techniquesThe three isolation techniquesConfinement: sharing less of your stateConfinement: sharing less of your state
Immutability: sharing read-only stateImmutability: sharing read-only state
Synchronization: using Synchronization: using lockslocks to serialize to serialize access to writeable shared stateaccess to writeable shared state
Thread 1: Thread 2:... ...lock(a) { ... ... lock(a) { ... ...
aalocklock
11
22Thread 1 Thread 1 lockslocks aaThread 2Thread 2 blocks blocks untiluntilaa is unlocked is unlocked
Concepts (2 of 2)Concepts (2 of 2)Invariants: logical correctness Invariants: logical correctness propertiesproperties
Safety vs. Liveness vs. EfficiencySafety vs. Liveness vs. EfficiencySafetySafety: program is “correct”: invariants : program is “correct”: invariants holdhold
Race conditions → violated invariantsRace conditions → violated invariants→ hard bugs→ hard bugs
LivenessLiveness: program makes progress: no : program makes progress: no deadlocksdeadlocks
EfficiencyEfficiency: as parallel as possible: as parallel as possible
Waiting (for another thread to do Waiting (for another thread to do something)something)
Consumer awaits producerConsumer awaits producer
Manager awaits workersManager awaits workers
Thread 1: Thread 2:lock(a) { ... ... lock(b) { ... ... lock(b) { ... ... lock(a) { ... ... } ... ... } ... ...} ... }
aalocklock
bblocklock
11
22
Deadlock!Deadlock!
Concepts Recap:Concepts Recap:Sequential vs. Sequential vs. MultithreadedMultithreadedSequential Programs Multithreaded
Programs
Memory is stable Memory is in flux(unless private, read-only,or protected by lock)
No locks needed Locks essential
Invariants hold on entry/exit to data structure methods
Invariants must hold when data’s lock not held
OK to access two data structures
If structures related, locks for both must be held
Deadlock can’t happen Deadlock is possible if multiple unordered locks
Key Managed Threading Key Managed Threading APIsAPIsThreading: creating concurrent Threading: creating concurrent
activitiesactivitiesThreadPool.QueueUserWorkItem(ThreadPool.QueueUserWorkItem(delegatedelegate))new Threadnew Thread(threadstart),(threadstart), Thread.Start(), Thread.Start(), Thread.Join()Thread.Join()
Locking: synchronizing (serializing) Locking: synchronizing (serializing) your shared memory accessesyour shared memory accesses
locklock((objobj) ) statement statement [[SyncLockSyncLock in VB] in VB]Monitor.Monitor.EnterEnter((objobj););try { try { statementstatement; }; }finally { Monitor.finally { Monitor.ExitExit((objobj); }); }
Waiting: scheduling workWaiting: scheduling workMonitor.Wait(Monitor.Wait(objobj))Monitor.Pulse(Monitor.Pulse(objobj), Monitor.PulseAll(), Monitor.PulseAll(objobj))
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
class MyList<T> { T[] items; int n;
void Add(T item) { items[n] = item; n++; } …}
class MyList<T> { T[] items; int n;
void Add(T item) { lock (this) { items[n] = item; n++; } } …}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
class MyList<T> { T[] items; int n;
void Add(T t) { lock(this) items[n] = t; lock(this) n++; } …}
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null
void Add(T t) { lock(this) { items[n] = t; n++; } } …}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
Use private lock Use private lock objectsobjects
And don’t lock on And don’t lock on Types or stringsTypes or strings
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null
void Add(T t) { lock(this) { items[n] = t; n++; } } …}
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null object lk = new object();
void Add(T t) { lock(lk) { items[n] = t; n++; } } …}
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null … static void ResetStats() { lock(typeof(MyList<T>)){ … } } …}
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null static object slk = new object(); … static void ResetStats() { lock(slk){ … } } …}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
Use private lock Use private lock objectsobjects
And don’t lock on And don’t lock on Types or stringsTypes or strings
Don’t call others’ Don’t call others’ code while you hold code while you hold lockslocks
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null object lk = new object();
void Add(T t) { lock(lk) { items[n] = t; n++; Listener.Notify(this); } } …}
class MyList<T> { T[] items; int n; // invariant: n is count // of valid items in list // and items[n] == null object lk = new object();
void Add(T t) { lock(lk) { items[n] = t; n++; } Listener.Notify(this); } …}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
Use private lock Use private lock objectsobjects
And don’t lock on And don’t lock on Types or stringsTypes or strings
Don’t call others’ Don’t call others’ code while you hold code while you hold lockslocks
Use appropriate Use appropriate lock granularitieslock granularities
class MyService { static object lk_all = …;
static void StaticDo() { lock(lk_all) { … } } void Do1() { lock(lk_all) { … } } void Do2() { lock(lk_all) { … } }}
class MyService { static object lk_all = …; object lk_inst = …;
static void StaticDo() { lock(lk_all) { … } } void Do1() { lock(lk_inst) { … } } void Do2() { lock(lk_inst) { … } }}
class MyService { static object lk_all = …; object lk_inst = …; object lk_op2 = …;
static void StaticDo() { lock(lk_all) { … } } void Do1() { lock(lk_inst) { … } } void Do2() { lock(lk_op2) { … } }}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
Use private lock Use private lock objectsobjects
And don’t lock on And don’t lock on Types or stringsTypes or strings
Don’t call others’ Don’t call others’ code while you hold code while you hold lockslocks
Use appropriate Use appropriate lock granularitieslock granularities
Order locks to Order locks to avoid deadlockavoid deadlock
class MyService { A a; // lock: lkA B b; // lock: lkB // order! lock(a) < lock(b) … void DoAB() { lock(a) lock(b) { a.Do(); b.Do(); } } void DoBA() { lock(a) lock(b) { b.Do(); a.Do(); } }}
class MyService { A a; B b; …
void DoAB() { lock(a) lock(b) { a.Do(); b.Do(); } } void DoBA() { lock(b) lock(a) { b.Do(); a.Do(); } }}
Locking Rules and Best Locking Rules and Best PracticesPractices
Lock over all Lock over all writeable shared statewriteable shared state
And always use the And always use the same lock for the given same lock for the given statestate
Lock over entire Lock over entire invariantinvariant
Use private lock Use private lock objectsobjects
And don’t lock on And don’t lock on Types or stringsTypes or strings
Don’t call others’ Don’t call others’ code while you hold code while you hold lockslocks
Use appropriate Use appropriate lock granularitieslock granularities
Order locks to Order locks to avoid deadlockavoid deadlock
public class Channel<T> { T t; bool full; object mon = new object();
public T Get() { … lock (mon) { while (!full) Monitor.Wait(mon); …
public void Put(T t) { lock (mon) { … full = true; Monitor.PulseAll(mon); …
while (!full) lock (mon) { Monitor.Wait(mon); …
lock (mon) { if (!full) Monitor.Wait(mon); …
lock (mon) { while (!full) Monitor.Wait(mon); …
Waiting Rules and Best Waiting Rules and Best PracticesPracticesWait exampleWait example
Use only the one true Use only the one true wait patternwait pattern
Test and retest Test and retest condition while condition while holding lockholding lock
Complete exampleComplete exampleCorrect (?) but could Correct (?) but could be more efficientbe more efficient
Pulse vs. PulseAllPulse vs. PulseAll
public class Channel<T> { T t; bool full; object mon = new object();
public T Get() { T t = default(T); lock (mon) { while (!full) Monitor.Wait(mon); t = this.t; full = false; Monitor.PulseAll(mon); } return t; } public void Put(T t) { lock (mon) { while (full) Monitor.Wait(mon); this.t = t; full = true; Monitor.PulseAll(mon); } }}
Concurrency for Concurrency for PerformancePerformance
Parallel PrimesCount Parallel PrimesCount ThreadingThreadingU
I Th
read
UI Th
read
UI Message QueueUI Message Queue(and Pumping)(and Pumping)
Thread PoolThread Pool
Thread Pool ThreadsThread Pool ThreadsRunWorkerAsyncRunWorkerAsync
QUWIQUWI
while
… M
onito
r.Wait
while
… M
onito
r.Wait
RunWorkerCompleted
RunWorkerCompleted
Other Concurrency Other Concurrency FacilitiesFacilities
WaitHandle,WaitHandle,AutoResetEvent,AutoResetEvent,ManualResetEvenManualResetEvent,t,Mutex, Mutex, SemaphoreSemaphore
Async pattern, IOAsync pattern, IO
Maybe laterMaybe laterInterlocked.*Interlocked.*
ReaderWriterLockReaderWriterLock
Thread.InterruptThread.Interrupt
Async delegatesAsync delegates
Waiting on events is Waiting on events is more flexible than more flexible than Monitor.WaitMonitor.Wait
Prefer ThreadPool overPrefer ThreadPool overexplicit thread mgmtexplicit thread mgmt
Prefer ThreadPool.QUWI Prefer ThreadPool.QUWI over async delegatesover async delegates
Prefer polling for Prefer polling for cancel over cancel over Thread.InterruptThread.Interrupt
Possible Future Concurrency Possible Future Concurrency ModelsModels
Looking Looking Way Way AheadAheadIn Search of Better Concurrency ModelsIn Search of Better Concurrency Models
Remember “old SW runs faster on new Remember “old SW runs faster on new PCs and faster still on next year’s PCs”?PCs and faster still on next year’s PCs”?Scaling up server apps Scaling up server apps – client apps? – client apps?Vision: what we did for memory Vision: what we did for memory managementmanagement(CLR v1), we aim to do for concurrency:(CLR v1), we aim to do for concurrency:
Using our evolved languages, libs, tools, Using our evolved languages, libs, tools, you’ll build & ship an app with lots of latent you’ll build & ship an app with lots of latent parallelismparallelismOn new HW, automatically apply extra HW On new HW, automatically apply extra HW resources to realize more latent parallelismresources to realize more latent parallelismMore tasks, more loops run in parallelMore tasks, more loops run in parallelAll without exposing latent races or All without exposing latent races or deadlocksdeadlocks
Looking AheadLooking AheadWorks and Explorations In ProgressWorks and Explorations In Progress
Developer ToolsDeveloper ToolsOpenMP (Visual C++ in Visual Studio 2005, OpenMP (Visual C++ in Visual Studio 2005, MSDN)MSDN)
Concur (see TLN309)Concur (see TLN309)
““Language Integrated Query” (see TLN306)Language Integrated Query” (see TLN306)
Microsoft Research (see FUN323)Microsoft Research (see FUN323)RaceTrack: detecting inconsistent lock usageRaceTrack: detecting inconsistent lock usage
Spec#: disciplined lockingSpec#: disciplined locking
CCωω: synchronization using chords (message : synchronization using chords (message joins)joins)
Software transactional memorySoftware transactional memory
Parallelism in HaskellParallelism in Haskell
Microsoft IncubationMicrosoft IncubationConcurrency and Coordination RuntimeConcurrency and Coordination Runtime
Looking AheadLooking AheadExample: Concurrency & Coordination Example: Concurrency & Coordination RuntimeRuntimeA local message passing library for A local message passing library for
highly concurrent teams of taskshighly concurrent teams of tasksTasks invoke other tasks by posting Tasks invoke other tasks by posting messages on their portsmessages on their portsTasks Tasks activateactivate message handlers to message handlers to accept (streams of) (joined) messagesaccept (streams of) (joined) messagesNo locks – you only send messages, No locks – you only send messages, and activate and execute handlersand activate and execute handlersStatus: incubation project; see Status: incubation project; see http://channel9.msdn.com/wiki/default.http://channel9.msdn.com/wiki/default.aspx/Channel9.ConcurrencyRuntimeaspx/Channel9.ConcurrencyRuntime
class WorkItem { public int m, n; // count primes in interval [m..n] public Port<int> pResult; // post the count here
public WorkItem(int m, int n, Port<int> pResult) { this.m = m; this.n = n; this.pResult = pResult; }}
void CountPrimes(int N, int chunkSize, Port<int> pTotal) { Port<WorkItem> pWork = new Port<WorkItem>(); Port<int> pResults = new Port<int>(); // post work item messages for (int i = 1; i <= N; i += chunkSize) pWork.post(new WorkItem(i, i+chunkSize-1, pResults));
// handle a stream of arbitrarily many work item messages activate( !pWork.with(delegate(WorkItem item) { // <count primes in interval [item.m .. item.n]> item.pResult.post(count); }));
// await (join over) all result messages then add them up activate( joinvariable<int>(pResults, N/chunkSize, delegate(int[] counts) { int total = 0; foreach (int count in counts) total += count; pTotal.post(total); }));}
Looking AheadLooking AheadExample: Software Transactional Example: Software Transactional MemoryMemoryShared memory + locks = Shared memory + locks = extra extra
complexitycomplexitySimple mistakes Simple mistakes → data races, deadlocks→ data races, deadlocks
Concurrent-componentConcurrent-component composition issues composition issues
STM: STM: atomic { a(); b(); c(); … }You think “I’m the only code on the You think “I’m the only code on the machine!”machine!”
STM observes your reads and writesSTM observes your reads and writes,, does does concurrency control, abort/retry for youconcurrency control, abort/retry for you
Automatic error clean up (back out) too!Automatic error clean up (back out) too!
Status: ‘research’Status: ‘research’
Conclusions / Call to Conclusions / Call to ActionAction
Concurrency is increasingly important Concurrency is increasingly important for responsiveness and parallelismfor responsiveness and parallelism
Multi-core era brings change and Multi-core era brings change and opportunityopportunity
Our platforms, languages, libraries, and Our platforms, languages, libraries, and tools will evolve to simplify tools will evolve to simplify concurrencyconcurrency
You now know key concepts and rules You now know key concepts and rules for programming with shared memory for programming with shared memory and locksand locks
TRY IT!TRY IT!
ResourcesResources
Herb Sutter, Herb Sutter, The Free Lunch Is OverThe Free Lunch Is Overhttp://www.gotw.ca/publications/concurrency-http://www.gotw.ca/publications/concurrency-ddj.htmddj.htm
Vance Morrison, Vance Morrison, What Every Dev Must Know What Every Dev Must Know About Multithreaded AppsAbout Multithreaded Apps, MSDN, Aug 05, , MSDN, Aug 05, Oct 05Oct 05http://msdn.microsoft.com/msdnmag/issues/05/08/Concuhttp://msdn.microsoft.com/msdnmag/issues/05/08/Concurrency/rrency/
MSDN Library / .NET Framework Advanced MSDN Library / .NET Framework Advanced Development / Development / Asynchronous CallsAsynchronous Calls docs docsAndrew Birrell, Andrew Birrell, Programming With Threads in Programming With Threads in C#C#http://research.microsoft.com/~birrell/papers/ThreadsCShhttp://research.microsoft.com/~birrell/papers/ThreadsCSharp.pdfarp.pdf
Doug Lea, Doug Lea, Concurrent Programming In JavaConcurrent Programming In JavaIntel Platform 2015Intel Platform 2015
CommunityCommunityRelated PDC talksRelated PDC talks
FUN405FUN405: : Programming with Concurrency #2 Programming with Concurrency #2 (4:15p today room 403AB)(4:15p today room 403AB)FUNL04: FUNL04: Tips & Tricks: Writing Performant Tips & Tricks: Writing Performant Managed Code Managed Code (Wed 12:30p lunch)(Wed 12:30p lunch)TLN306: TLN306: The .NET Language Integrated Query The .NET Language Integrated Query Framework Framework (Wed 1:45p)(Wed 1:45p)FUN323FUN323: : Microsoft Research: Future Possibilities Microsoft Research: Future Possibilities in Concurrencyin Concurrency (Fri 8:30a) (Fri 8:30a)TLN309TLN309: : C++: Future Directions in Language C++: Future Directions in Language InnovationInnovation (Fri 10:30a) (Fri 10:30a)DAT301: DAT301: High Perf. Computing with the Windows High Perf. Computing with the Windows Server Compute Cluster SolutionServer Compute Cluster Solution (Tue 1:00p (at (Tue 1:00p (at home on DVD))home on DVD))
Ask the ExpertsAsk the ExpertsFundamentals/Performance/Concurrency (Thu Fundamentals/Performance/Concurrency (Thu 6:30p)6:30p)
Questions?Questions? (Evals (Evals please!)please!)
© 2005 Microsoft Corporation. All rights reserved.This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.
Appendix: Parallel PrimesCount source Appendix: Parallel PrimesCount source (1)(1)// NB: quick hack by Jan Gray, no warranties of fitness, etc.// NB: quick hack by Jan Gray, no warranties of fitness, etc.// For illustrative purposes only.// For illustrative purposes only.
using System;using System;using System.ComponentModel;using System.ComponentModel;using System.Diagnostics;using System.Diagnostics;using System.Windows.Forms;using System.Windows.Forms;using System.Threading;using System.Threading;
namespace Primes {namespace Primes { public partial class CountPrimesForm : Form {public partial class CountPrimesForm : Form { private Stopwatch stopwatch = new Stopwatch();private Stopwatch stopwatch = new Stopwatch(); public CountPrimesForm() {public CountPrimesForm() { InitializeComponent();InitializeComponent(); }} private void button1_Click(object sender, EventArgs e) {private void button1_Click(object sender, EventArgs e) { result.Text = "working...";result.Text = "working..."; startButton.Enabled = false;startButton.Enabled = false; cancelButton.Enabled = true;cancelButton.Enabled = true; Update();Update();
stopwatch.Reset();stopwatch.Reset(); stopwatch.Start();stopwatch.Start(); bg.RunWorkerAsync((long)n.Value);bg.RunWorkerAsync((long)n.Value); }} private void bg_DoWork(object sender, DoWorkEventArgs e) {private void bg_DoWork(object sender, DoWorkEventArgs e) { long n = (long)e.Argument;long n = (long)e.Argument; long count = (new Primes()).CountPrimes(n, bg);long count = (new Primes()).CountPrimes(n, bg); if (count == -1)if (count == -1) e.Result = "cancelled";e.Result = "cancelled"; elseelse e.Result = String.Format("{0} primes <= {1}", count, n);e.Result = String.Format("{0} primes <= {1}", count, n); }} private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { result.Text = String.Format("{0} (after {1} s)", e.Result, stopwatch.ElapsedMilliseconds/1000.0);result.Text = String.Format("{0} (after {1} s)", e.Result, stopwatch.ElapsedMilliseconds/1000.0); progressBar1.Value = 0;progressBar1.Value = 0; startButton.Enabled = true;startButton.Enabled = true; cancelButton.Enabled = false;cancelButton.Enabled = false; }} private void cancelButton_Click(object sender, EventArgs e) {private void cancelButton_Click(object sender, EventArgs e) { bg.CancelAsync();bg.CancelAsync(); }} private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage;progressBar1.Value = e.ProgressPercentage; }} }}}}
Appendix: Parallel PrimesCount source Appendix: Parallel PrimesCount source (2)(2)// NB: quick hack by Jan Gray, no warranties of fitness, etc.// NB: quick hack by Jan Gray, no warranties of fitness, etc.// For illustrative purposes only.// For illustrative purposes only.
using System;using System;using System.Collections.Generic;using System.Collections.Generic;using System.ComponentModel;using System.ComponentModel;using System.Threading;using System.Threading;
namespace Primes {namespace Primes { public class Primes {public class Primes {/*!*/ // condition variable 'mon' -- pulsed whenever completedTasks changes/*!*/ // condition variable 'mon' -- pulsed whenever completedTasks changes private object mon = new object();private object mon = new object(); // shared read-only (after initialization)// shared read-only (after initialization) private List<long> lowPrimes = new List<long>();private List<long> lowPrimes = new List<long>(); // shared writable, guarded by lock(mon)// shared writable, guarded by lock(mon) private long totalCount;private long totalCount; private int completedTasks;private int completedTasks;
public long CountPrimes(long n, BackgroundWorker bg) {public long CountPrimes(long n, BackgroundWorker bg) { // build shared read-only low primes table// build shared read-only low primes table CountPrimesInRange(2, (int)Math.Sqrt(n) + 1, bg, true);CountPrimesInRange(2, (int)Math.Sqrt(n) + 1, bg, true);
// divvy up primes counting work into tasks of 'chunkSize' integers// divvy up primes counting work into tasks of 'chunkSize' integers const int chunkSize = 1000;const int chunkSize = 1000; int tasks = 0;int tasks = 0;
/*!*/ lock (mon) {/*!*/ lock (mon) { totalCount = 0;totalCount = 0; completedTasks = 0;completedTasks = 0; }}
// issue primes finding work items// issue primes finding work items for (long i = 2; i <= n; i += chunkSize) {for (long i = 2; i <= n; i += chunkSize) { ++tasks;++tasks;/*!*/ ThreadPool.QueueUserWorkItem(Callback,/*!*/ ThreadPool.QueueUserWorkItem(Callback, new Args(i, Math.Min(i + chunkSize - 1, n), bg));new Args(i, Math.Min(i + chunkSize - 1, n), bg)); }}
// wait until all tasks are completed// wait until all tasks are completed/*!*/ lock (mon) {/*!*/ lock (mon) { while (completedTasks < tasks && !bg.CancellationPending) {while (completedTasks < tasks && !bg.CancellationPending) { bg.ReportProgress(100 * completedTasks / tasks);bg.ReportProgress(100 * completedTasks / tasks); Monitor.Wait(mon);Monitor.Wait(mon); }} }}
return bg.CancellationPending ? -1 : totalCount;return bg.CancellationPending ? -1 : totalCount; }} // threadpool callback arguments// threadpool callback arguments class Args {class Args { public long m, n;public long m, n; public BackgroundWorker bg;public BackgroundWorker bg; public Args(long m, long n, BackgroundWorker bg) {public Args(long m, long n, BackgroundWorker bg) { this.m = m;this.m = m; this.n = n;this.n = n; this.bg = bg;this.bg = bg; }} }} private void Callback(object obj) {private void Callback(object obj) { Args args = (Args)obj;Args args = (Args)obj; long rangeCount = CountPrimesInRange(args.m, args.n, args.bg, false);long rangeCount = CountPrimesInRange(args.m, args.n, args.bg, false);
/*!*/ lock (mon) {/*!*/ lock (mon) { totalCount += rangeCount;totalCount += rangeCount; ++completedTasks;++completedTasks; Monitor.Pulse(mon);Monitor.Pulse(mon); }} }} private long CountPrimesInRange(long m, long n, BackgroundWorker bg, bool addToLowPrimes) {private long CountPrimesInRange(long m, long n, BackgroundWorker bg, bool addToLowPrimes) { long count = 0;long count = 0; for (long i = m; i <= n; i++) {for (long i = m; i <= n; i++) { if (bg.CancellationPending)if (bg.CancellationPending) return -1;return -1; foreach (long p in lowPrimes) {foreach (long p in lowPrimes) { if (p * p > i)if (p * p > i) goto prime;goto prime; if (i % p == 0)if (i % p == 0) goto composite;goto composite; }}prime: ++count;prime: ++count; if (addToLowPrimes)if (addToLowPrimes) lowPrimes.Add(i);lowPrimes.Add(i);composite: ;composite: ; }} return count;return count; }} }}}}
Threading Concepts (3 of Threading Concepts (3 of 2)2)Memory Consistency ModelsMemory Consistency Models
Caches, optimizations can cause Caches, optimizations can cause observed loads and stores to “reorder” in observed loads and stores to “reorder” in other threadsother threads
““This makes my brain hurt!”This makes my brain hurt!”
A non-issue if A non-issue if allall your writeable shared your writeable shared memory accesses are under locksmemory accesses are under locks
Resist temptation to go “lock free”!Resist temptation to go “lock free”!
(See also)(See also)FUN405: FUN405: Programming with Concurrency Programming with Concurrency #2 #2 (4:15p today room 403AB)(4:15p today room 403AB)
Vance Morrison, MSDN, Oct 05Vance Morrison, MSDN, Oct 05