Programming C#

Florian Rappl, Department of Theoretical Physics, University of Regensburg

Programming C#

Day 4: Threads and tasks, TPL, await and async and user controls

Content

  • Sets and LINQ
  • The message loop, threads and GUI synchronization
  • Wrapping threads in tasks
  • The Task Parallel Library (TPL)
  • Considerations for multi-threading
  • Using the asynchronous keywords
  • An overview of available controls
  • Building own user controls

Sets and LINQ

  • Reminder: LINQ execution is deferred!
  • LINQ is specialized on handled collections
  • Collections can be quite similar to sets
  • There are several methods for doing set math
  • Unions, intersections, exceptions, ...
  • Quite important is certainly Distinct()

Venn diagrams

→ Example - Sets and LINQ

LinqSets.cs

The message loop

  • How does a GUI work? It's a big loop
  • This is called the message loop
  • The OS queues messages for our app
  • These messages get pumped once the app is idle
  • Ergo the idle state of an app is very important
  • Doing too much work will result in a non-responsive app

The cure: threads

  • Hence the OS has a model called: threads
  • Every app comes with 1 thread: the GUI thread
  • Advantage with several (CPU) cores: prob. faster execution
  • Advantage even with just a single core: responsive UI
  • The reason is that the OS schedules CPU time
  • The only question is now: How can we create threads?

Creating threads

  • We need a method that should run in that thread
  • The class Thread represents a thread
  • The constructor requires a delegate of the method to run
  • The namespace System.Threading contains the class and more
  • Running Start() will run the method in another thread
  • Important: Exceptions from other threads will bubble up!

→ Example - Threads

Threads.cs

Problems with threads

  • Threads are running concurrently
  • Spawning multiple threads results in overhead
  • Consider using the ThreadPool for many threads
  • Avoid race conditions, i.e. solving non-independent problems
  • Biggest problem: How to communicate between threads?
  • Another problem: Changing the UI is not possible

Thread barriers

  • C# introduces the lock keyword
  • The lock blocks usage on certain lines of code
  • Barriers help to reduce race conditions
  • The barrier status (set / unset) is determined by a pointer
  • A pointer is here just given by a reference type
var obj = new object();
lock(obj) { /* locked! */ }

Thread synchronization

  • Every WinForms control has an Invoke() method
  • In WPF we can use the (generic) Dispatcher property
  • However, the most generic way of doing thread-safe UI calls is over the SynchronizationContext class
  • The static property Current carries the sync. context
  • This property is set by e.g. a WinForms Form instance

→ Example - Thread synchronization

ThreadSync.cs

Tasks

  • Much more modern and powerful: Tasks!
  • Concept: Resources (threads, ...) are handled by the library
  • We have a very optimized (and managed) thread pool
  • Tasks can be connected, scheduled and synchronized
  • Important: Exceptions do not bubble up unless requested!
  • Nowadays everything is centered around the Task class

The TPL

  • A set of useful classes and methods for tasks
  • Very elegant: using Parallel.For() for huge loops
  • Be careful with: race conditions & overhead due to creation
  • The TPL also introduced PLINQ (parallel LINQ)
  • Use parallel queries by calling the AsParallel() extension
  • Be aware of race conditions and shared resources
  • Another great feature of the TPL: new (concurrent) types

Structure of the TPL

Considerations for multi-threading

  • The workload has to be big enough
  • At least as much instructions as creating and ending the thread
  • Just running a problem on more cores is not equal more speed
  • Always think about IO-bound vs CPU-bound
  • IO-bound? 1 thread that is not the GUI thread is enough
  • CPU-bound? Up to N threads (for N cores) additional threads
  • Reduce communication to a minimum

→ Example - Task Parallel Library

Tasks.cs

Await my async!

  • C# 5 introduces two new keywords: await and async
  • By using async we mark functions as being asynchronous
  • This enables us to use the await keyword
  • This DOES not spawn a new thread
  • The default return value is Task
  • The purpose is to write sequential code, which runs concurrently

Await my async!

  • The method is entered (doing UI)
  • Calling long-lasting function
  • The UI is meanwhile responsive
  • Once the task is finished ...
  • ... the method is resuming
  • Doing some UI stuff again

Do's and don'ts

  • await transforms a Task<T> in T
  • i.e. the variable a in var a = await MyFoo(); of async Task<int>Foo() will be an integer
  • Really important here: We can use try-catch
  • We could also use async over sync with Task.Run()
  • Of course the opposite is also possible: sync over async
  • Here we just have to omit the await

Common mistakes

  • async void should only be used with event handlers
  • Using sync over async with an async function that switches to the UI
  • This will result in a deadlock, i.e. the UI is dead
  • Spawning too many (parallel) tasks
  • Using a lambda that returns void instead of Task

→ Example - Await and async

AwaitAsync.cs

Controls in Windows Forms

  • All common Windows controls exist
  • Some new ones have been integrated as well
  • ComboBox, TextBox, Label, Button
  • Or with children: TabControl, Panel, GroupBox
  • Specialized input: NumericUpDown, DateTimePicker
  • Each control has a big range of (mostly useful) properties

Creating custom controls

  • Most basic starting point: Inherit from Component
  • Far better: Derive from Control
  • Option with designer: UserControl
  • Or pick one like ScrollableControl
  • In most cases we have to do the drawing
  • Drawing is done over GDI+, more about it later

→ Example - Create a control

BlinkLabel.zip

All available presentations

More questions? Just mail!

MVP

Florian Rappl, MVP Visual C#