github twitter email rss
.Net
0001 Jun 1
26 minutes read

.Net

DotNet Core

dotnet restore --runtime osx.10.10-x64

DOTNET_HOME=$(readlink -f $(brew –prefix dotnet))/libexec

C# Programming Guide

http://msdn.microsoft.com/en-us/library/67ef8sbd.aspx

Libraries

rest

https://github.com/restsharp/RestSharp/wiki/Getting-Started

key value cache

https://github.com/github/Akavache

mono

http://www.mono-project.com/Coding_Guidelines#Best_Practices
http://docs.go-mono.com/

MVP Model View Presenter

http://evolutionnet.codeplex.com
http://claymore.codeplex.com
http://www.mvcsharp.org

IoC, dependency injection

http://docs.structuremap.net
http://commonservicelocator.codeplex.com/

opengl

http://sharpgl.codeplex.com
http://code.google.com/p/gorgonlib/
http://slimdx.org/

search engine

http://incubator.apache.org/lucene.net/

CLR via. C

Method Signatures

  • arguments as IList or IEnumerable better than List

Threads and Process priorities

There are 0 - 31 threads priority levels.
This levels abstracted by:

  • Process priority class: Idle, Below Normal, Normal, Above Normal, High, Realtime
  • Relative thread priorities: Idle, Lowest, Below Normal, Normal, Above Normal, Highest, Time-Critical


|Relative Thread| Process Priority Class
|priority |
|—————|—————————————————————–
| | Idle | Below Normal | Normal | Above Normal | High | Realtime
|Time-Critical | 15 | 15 | 15 | 15 | 15 | 31
|Highest | 6 | 8 | 10 | 12 | 15 | 26
|Above Normal | 5 | 7 | 9 | 11 | 14 | 25
|Normal | 4 | 6 | 8 | 10 | 13 | 24
|Below Normal | 3 | 5 | 7 | 9 | 12 | 23
|Lowest | 2 | 4 | 6 | 8 | 11 | 22

|Idle | 1 | 1 | 1 | 1 | 1 | 16

.NET CLR allow only thread priorities: Lowest, BelowNormal, Normal, AboveNormal, Highest

  • AppDomain and Thread classes expose the CLR’s view of an AppDomain and thread
  • System.Diagnostics Process class and a ProcessThread class provide Windows view of a process and thread
  • foreground and background threads in CLR

    using System;
    using System.Threading;

    public static class Program {
    public static void Main() {

      // Create a new thread (defaults to foreground) 
      Thread t = new Thread(Worker); 
    
      // Make the thread a background thread 
      t.IsBackground = true; 
    
      t.Start(); // Start the thread 
      // If t is a foreground thread, the application won't die for about 10 seconds 
      // If t is a background thread, the application dies immediately 
      Console.WriteLine("Returning from Main"); 
    

    }

    private static void Worker() {

      Thread.Sleep(10000);  // Simulate doing 10 seconds of work 
    
      // The following line only gets displayed if this code is executed by a foreground thread 
      Console.WriteLine("Returning from Worker"); 
    

    }
    }

Dedicated threads

delegate void ParameterizedThreadStart(Object obj);

public sealed class Thread : CriticalFinalizerObject, ... {  
    public Thread(ParameterizedThreadStart start);  
    // Less commonly used constructors are not shown here   
}

public static class Program {  
   public static void Main() {  
      Console.WriteLine("Main thread: starting a dedicated thread " +  
         "to do an asynchronous operation");  
      Thread dedicatedThread = new Thread(ComputeBoundOp);  
      dedicatedThread.Start(5);  

      Console.WriteLine("Main thread: Doing other work here...");  
      Thread.Sleep(10000);     // Simulating other work (10 seconds)  

      dedicatedThread.Join();  // Wait for thread to terminate  
      Console.WriteLine("Hit <Enter> to end this program...");  
      Console.ReadLine();  
   }  

   // This method's signature must match the ParameterizedThreadStart delegate  
   private static void ComputeBoundOp(Object state) {  
      // This method is executed by a dedicated thread   

      Console.WriteLine("In ComputeBoundOp: state={0}", state);  
      Thread.Sleep(1000);  // Simulates other work (1 second)  

      // When this method returns, the dedicated thread dies  
   }  
}

System.Threading.ThreadPool.QueueUserWorkItem
System.Threading.Timer
System.Threading.Thread
System.Threading.Tasks

Thread pool

static Boolean QueueUserWorkItem(WaitCallback callBack);  
static Boolean QueueUserWorkItem(WaitCallback callBack, Object state);

using System;  
using System.Threading;  

public static class Program {  
   public static void Main() {  
      Console.WriteLine("Main thread: queuing an asynchronous operation");  
      ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5);  
      Console.WriteLine("Main thread: Doing other work here...");  
      Thread.Sleep(10000);  // Simulating other work (10 seconds)  
      Console.WriteLine("Hit <Enter> to end this program...");  
      Console.ReadLine();  
   }  

   // This method's signature must match the WaitCallback delegate  
   private static void ComputeBoundOp(Object state) {  
      // This method is executed by a thread pool thread     
      Console.WriteLine("In ComputeBoundOp: state={0}", state);  
      Thread.Sleep(1000);  // Simulates other work (1 second)  

      // When this method returns, the thread goes back  
      // to the pool and waits for another task  
   }  
}

execution context

public sealed class ExecutionContext : IDisposable, ISerializable { 
   [SecurityCritical] public static AsyncFlowControl SuppressFlow(); 
   public static void RestoreFlow(); 
   public static Boolean IsFlowSuppressed(); 

   // Less commonly used methods are not shown 
}


public static void Main() { 
   // Put some data into the Main thread's logical call context 
   CallContext.LogicalSetData("Name", "Jeffrey"); 

   // Initiate some work to be done by a thread pool thread 
   // The thread pool thread can access the logical call context data  
   ThreadPool.QueueUserWorkItem( 
      state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name")));


   // Now, suppress the flowing of the Main thread's execution context 
   ExecutionContext.SuppressFlow(); 
    // Initiate some work to be done by a thread pool thread 
    // The thread pool thread CANNOT access the logical call context data 
   ThreadPool.QueueUserWorkItem( 
      state => Console.WriteLine("Name={0}", CallContext.LogicalGetData("Name"))); 

   // Restore the flowing of the Main thread's execution context in case 
   // it employs more thread pool threads in the future 
   ExecutionContext.RestoreFlow(); 
   ... 
   Console.ReadLine(); 

    //// Result
    // Name=Jeffrey 
    // Name=
}

Cooperative Cancellation and Timeout

System.Threading.CancellationTokenSource 

public sealed class CancellationTokenSource : IDisposable {  // A reference type 
    public CancellationTokenSource(); 

    public Boolean IsCancellationRequested { get; } 
    public CancellationToken Token { get; } 

    public void Cancel();  // Internally, calls Cancel passing false 
    public void Cancel(Boolean throwOnFirstException); 
    ... 
}

public struct CancellationToken {  // A value type 
   public static CancellationToken None { get; }  // Very convenient 

   public Boolean    IsCancellationRequested { get; } // Called by non­Task invoked operations 
   public void       ThrowIfCancellationRequested();  // Called by Task­invoked operations 

   // WaitHandle is signaled when the CancellationTokenSource is canceled 
   public WaitHandle WaitHandle { get; }   
   // GetHashCode, Equals, operator== and operator!= members are not shown 

   public Boolean CanBeCanceled { get; }  // Rarely used 

   public CancellationTokenRegistration Register(Action<Object> callback, Object state, 
      Boolean useSynchronizationContext);  // Simpler overloads not shown 
}


internal static class CancellationDemo { 
   public static void Main() { 
      CancellationTokenSource cts = new CancellationTokenSource(); 

      // Pass the CancellationToken and the number­to­count­to into the operation 
      ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 1000)); 

      Console.WriteLine("Press <Enter> to cancel the operation."); 
      Console.ReadLine(); 
      cts.Cancel();  // If Count returned already, Cancel has no effect on it 
      // Cancel returns immediately, and the method continues running here... 

      Console.ReadLine(); 
   } 

   private static void Count(CancellationToken token, Int32 countTo) { 
      for (Int32 count = 0; count <countTo; count++) { 
         if (token.IsCancellationRequested) { 
            Console.WriteLine("Count is cancelled"); 
            break; // Exit the loop to stop the operation 
         } 

         Console.WriteLine(count); 
         Thread.Sleep(200);   // For demo, waste some time 
      } 
      Console.WriteLine("Count is done"); 
   } 
}



// Create a CancellationTokenSource 
var cts1 = new CancellationTokenSource(); 
cts1.Token.Register(() => Console.WriteLine("cts1 canceled")); 

// Create another CancellationTokenSource 
var cts2 = new CancellationTokenSource(); 
cts2.Token.Register(() => Console.WriteLine("cts2 canceled")); 

// Create a new CancellationTokenSource that is canceled when cts1 or ct2 is canceled 
var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cts1.Token, cts2.Token); 
linkedCts.Token.Register(() => Console.WriteLine("linkedCts canceled")); 

// Cancel one of the CancellationTokenSource objects (I chose cts2) 
cts2.Cancel(); 

// Display which CancellationTokenSource objects are canceled 
Console.WriteLine("cts1 canceled={0}, cts2 canceled={1}, linkedCts canceled={2}", 
   cts1.IsCancellationRequested, cts2.IsCancellationRequested,  
linkedCts.IsCancellationRequested); 



public sealed class CancellationTokenSource : IDisposable {  // A reference type 
   public CancellationTokenSource(Int32 millisecondsDelay); 
   public CancellationTokenSource(TimeSpan delay); 

   public void CancelAfter(Int32 millisecondsDelay); 
   public void CancelAfter(TimeSpan delay); 
   ... 
}

Tasks

System.Threading.Tasks 

ThreadPool.QueueUserWorkItem(ComputeBoundOp, 5); // Calling QueueUserWorkItem 
new Task(ComputeBoundOp, 5).Start();             // Equivalent of preceding using Task 
Task.Run(() => ComputeBoundOp(5));               // Another equivalent


[Flags, Serializable] 
public enum TaskCreationOptions { 
   None             = 0x0000,// The default 

   // Hints to the TaskScheduler that you want this task to run sooner than later. 
   PreferFairness      = 0x0001, 

   // Hints to the TaskScheduler that it should more aggressively create thread pool threads. 
   LongRunning        = 0x0002, 

   // Always honored: Associates a Task with its parent Task (discussed shortly) 
   AttachedToParent   = 0x0004, 

   // If a task attempts to attach to this parent task, it is a normal task, not a child task. 
   DenyChildAttach    = 0x0008, 

   // Forces child tasks to use the default scheduler as opposed to the parent’s scheduler. 
   HideScheduler      = 0x0010 
}


// Create a Task (it does not start running now) 
Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000000000); 

// You can start the task sometime later 
t.Start();  

// Optionally, you can explicitly wait for the task to complete 
t.Wait(); // FYI: Overloads exist accepting timeout/CancellationToken 

// You can get the result (the Result property internally calls Wait) 
Console.WriteLine("The Sum is: " + t.Result); // An Int32 value


To help you detect unobserved exceptions, you can register a callback method with TaskScheduler’s static UnobservedTaskException event.


private static Int32 Sum(CancellationToken ct, Int32 n) { 
   Int32 sum = 0; 
   for (; n > 0; n­­) { 

      // The following line throws OperationCanceledException when Cancel  
      // is called on the CancellationTokenSource referred to by the token 
      ct.ThrowIfCancellationRequested(); 

      checked { sum += n; }   // if n is large, this will throw System.OverflowException 
   } 
   return sum; 
}

CancellationTokenSource cts = new CancellationTokenSource(); 
Task<Int32> t = Task.Run(() => Sum(cts.Token, 1000000000), cts.Token); 

// Sometime later, cancel the CancellationTokenSource to cancel the Task 
cts.Cancel(); // This is an asynchronous request, the Task may have completed already 

try { 
   // If the task got canceled, Result will throw an AggregateException 
   Console.WriteLine("The sum is: " + t.Result);   // An Int32 value 
} 
catch (AggregateException x) { 
   // Consider any OperationCanceledException objects as handled.  
   // Any other exceptions cause a new AggregateException containing 
   // only the unhandled exceptions to be thrown 
   x.Handle(e => e is OperationCanceledException); 

   // If all the exceptions were handled, the following executes 
   Console.WriteLine("Sum was canceled"); 
}


// Create and start a Task, continue with another task 
Task<Int32> t = Task.Run(() => Sum(CancellationToken.None, 10000)); 

// ContinueWith returns a Task but you usually don't care 
Task cwt = t.ContinueWith(task => Console.WriteLine("The sum is: " + task.Result));

[Flags, Serializable] 
public enum TaskContinuationOptions { 
   None             = 0x0000,// The default 

   // Hints to the TaskScheduler that you want this task to run sooner than later. 
   PreferFairness      = 0x0001, 

   // Hints to the TaskScheduler that it should more aggressively create thread pool threads. 
   LongRunning        = 0x0002, 

   // Always honored: Associates a Task with its parent Task (discussed shortly) 
   AttachedToParent   = 0x0004, 

   // If a task attempts to attach to this parent task, an InvalidOperationException is thrown. 
   DenyChildAttach    = 0x0008, 

   // Forces child tasks to use the default scheduler as opposed to the parent’s scheduler. 
   HideScheduler      = 0x0010, 

   // Prevents completion of the continuation until the antecedent has completed. 
   LazyCancellation   = 0x0020, 

   // This flag indicates that you want the thread that executed the first task to also 
   // execute the ContinueWith task. If the first task has already completed, then the 
   // thread calling ContinueWith will execute the ContinueWith task. 
   ExecuteSynchronously  = 0x80000, 

   // These flags indicate under what circumstances to run the ContinueWith task 
   NotOnRanToCompletion  = 0x10000, 
   NotOnFaulted          = 0x20000, 
   NotOnCanceled         = 0x40000, 

   // These flags are convenient combinations of the above three flags 
   OnlyOnCanceled        = NotOnRanToCompletion | NotOnFaulted, 
   OnlyOnFaulted         = NotOnRanToCompletion | NotOnCanceled, 
   OnlyOnRanToCompletion = NotOnFaulted         | NotOnCanceled, 
}

// Create and start a Task, continue with multiple other tasks 
Task<Int32> t = Task.Run(() => Sum(10000));  
// Each ContinueWith returns a Task but you usually don't care 
t.ContinueWith(task => Console.WriteLine("The sum is: " + task.Result), 
   TaskContinuationOptions.OnlyOnRanToCompletion); 

t.ContinueWith(task => Console.WriteLine("Sum threw: " + task.Exception.InnerException),  
   TaskContinuationOptions.OnlyOnFaulted); 

t.ContinueWith(task => Console.WriteLine("Sum was canceled"),  
   TaskContinuationOptions.OnlyOnCanceled);

Child tasks

Task<Int32[]> parent = new Task<Int32[]>(() => { 
   var results = new Int32[3];   // Create an array for the results 

   // This tasks creates and starts 3 child tasks 
   new Task(() => results[0] = Sum(10000), TaskCreationOptions.AttachedToParent).Start(); 
   new Task(() => results[1] = Sum(20000), TaskCreationOptions.AttachedToParent).Start(); 
   new Task(() => results[2] = Sum(30000), TaskCreationOptions.AttachedToParent).Start(); 

   // Returns a reference to the array (even though the elements may not be initialized yet) 
   return results;  
}); 

// When the parent and its children have run to completion, display the results 
var cwt = parent.ContinueWith( 
   parentTask => Array.ForEach(parentTask.Result, Console.WriteLine)); 

// Start the parent Task so it can start its children 
parent.Start();

Tasks state

public enum TaskStatus { 
   // These flags indicate the state of a Task during its lifetime: 
   Created,             // Task created explicitly; you can manually Start() this task 
   WaitingForActivation,// Task created implicitly; it starts automatically 

   WaitingToRun,  // The task was scheduled but isn’t running yet 
   Running,       // The task is actually running 

   // The task is waiting for children to complete before it considers itself complete 
   WaitingForChildrenToComplete, 

   // A task's final state is one of these: 
   RanToCompletion, 
   Canceled, 
   Faulted 
}

TaskFactory, TaskFactory

Task parent = new Task(() => { 
   var cts = new CancellationTokenSource(); 
   var tf  = new TaskFactory<Int32>(cts.Token, TaskCreationOptions.AttachedToParent,  
      TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); 

   // This task creates and starts 3 child tasks 
   var childTasks = new[] { 
      tf.StartNew(() => Sum(cts.Token, 10000)), 
      tf.StartNew(() => Sum(cts.Token, 20000)), 
      tf.StartNew(() => Sum(cts.Token, Int32.MaxValue))  // Too big, throws OverflowException 
   }; 

   // If any of the child tasks throw, cancel the rest of them 
   for (Int32 task = 0; task < childTasks.Length; task++) 
      childTasks[task].ContinueWith( 
         t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted); 

   // When all children are done, get the maximum value returned from the  
   // non­faulting/canceled tasks. Then pass the maximum value to another  
   // task that displays the maximum result 
   tf.ContinueWhenAll( 
      childTasks,  
      completedTasks =>  
         completedTasks.Where(t => t.Status == TaskStatus.RanToCompletion).Max(t => t.Result), 
      CancellationToken.None) 
         .ContinueWith(t =>Console.WriteLine("The maximum is: " + t.Result), 
            TaskContinuationOptions.ExecuteSynchronously); 
}); 
// When the children are done, show any unhandled exceptions too 
parent.ContinueWith(p => { 
   // I put all this text in a StringBuilder and call Console.WriteLine just once  
   // because this task could execute concurrently with the task above & I don't  
   // want the tasks' output interspersed 
   StringBuilder sb = new StringBuilder( 
      "The following exception(s) occurred:" + Environment.NewLine); 

   foreach (var e in p.Exception.Flatten().InnerExceptions)  
      sb.AppendLine("   "+ e.GetType().ToString()); 
   Console.WriteLine(sb.ToString()); 
}, TaskContinuationOptions.OnlyOnFaulted);
// Start the parent Task so it can start its children 
parent.Start();

Task Schedulers

  • thread pool task scheduler
  • synchronization context task scheduler
  • IOTaskScheduler This task scheduler queues tasks to the thread pool’s I/O threads instead
    of its worker threads.
  • LimitedConcurrencyLevelTaskScheduler This task scheduler allows no more than n (a
    constructor parameter) tasks to execute simultaneously.
  • OrderedTaskScheduler This task scheduler allows only one task to execute at a time. This
    class is derived from LimitedConcurrencyLevelTaskScheduler and just passes 1 for n.
  • PrioritizingTaskScheduler This task scheduler queues tasks to the CLR’s thread pool. After
    this has occurred, you can call Prioritize to indicate that a Task should be processed be-
    fore all normal tasks (if it hasn’t been processed already). You can call Deprioritize to make
    a Task be processed after all normal tasks.
  • ThreadPerTaskScheduler This task scheduler creates and starts a separate thread for each
    task; it does not use the thread pool at all.

http://code.msdn.microsoft.com/ParExtSamples

internal sealed class MyForm : Form { 
   private readonly TaskScheduler m_syncContextTaskScheduler; 
   public MyForm() { 
      // Get a reference to a synchronization context task scheduler 
      m_syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

      Text = "Synchronization Context Task Scheduler Demo"; 
      Visible = true; Width = 600; Height = 100; 
   } 

   private CancellationTokenSource m_cts; 

   protected override void OnMouseClick(MouseEventArgs e) { 
      if (m_cts != null) { // An operation is in flight, cancel it 
         m_cts.Cancel(); 
         m_cts = null; 
      } else { // An operation is not in flight, start it 
         Text = "Operation running"; 
         m_cts = new CancellationTokenSource(); 

         // This task uses the default task scheduler and executes on a thread pool thread 
         Task<Int32> t = Task.Run(() => Sum(m_cts.Token, 20000), m_cts.Token); 

         // These tasks use the sync context task scheduler and execute on the GUI thread 
         t.ContinueWith(task => Text = "Result: " + task.Result,  
            CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, 
            m_syncContextTaskScheduler); 

         t.ContinueWith(task => Text = "Operation canceled",  
            CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, 
            m_syncContextTaskScheduler); 

         t.ContinueWith(task => Text = "Operation faulted", 
            CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, 
            m_syncContextTaskScheduler); 
      } 
      base.OnMouseClick(e); 
   } 
}

System.Threading.Tasks.Parallel

// One thread performs all this work sequentially 
for (Int32 i = 0; i < 1000; i++) DoWork(i);

you can instead get multiple thread pool threads to assist in performing this work by using the 
Parallel class’s For method.

// The thread pool’s threads process the work in parallel 
Parallel.For(0, 1000, i => DoWork(i));

Similarly, if you have a collection, instead of doing this:

// One thread performs all this work sequentially 
foreach (var item in collection) DoWork(item);

you can do this.

// The thread pool's threads process the work in parallel 
Parallel.ForEach(collection, item => DoWork(item));

// The thread pool’s threads execute the methods in parallel 
Parallel.Invoke( 
   () => Method1(),  
   () => Method2(),  
   () => Method3());


private static Int64 DirectoryBytes(String path, String searchPattern,  
   SearchOption searchOption) { 
   var files = Directory.EnumerateFiles(path, searchPattern, searchOption); 
   Int64 masterTotal = 0; 

   ParallelLoopResult result = Parallel.ForEach<String, Int64>( 
      files, 

      () => { // localInit: Invoked once per task at start 
         // Initialize that this task has seen 0 bytes 
         return 0;   // Set taskLocalTotal initial value to 0 
      }, 

      (file, loopState, index, taskLocalTotal) => { // body: Invoked once per work item 
         // Get this file's size and add it to this task's running total 
         Int64 fileLength = 0; 
         FileStream fs = null; 
         try { 
            fs = File.OpenRead(file); 
            fileLength = fs.Length; 
         }  
         catch (IOException) { /* Ignore any files we can't access */ } 
         finally { if (fs != null) fs.Dispose(); } 
         return taskLocalTotal + fileLength; 
      }, 

      taskLocalTotal => { // localFinally: Invoked once per task at end 
         // Atomically add this task's total to the "master" total 
         Interlocked.Add(ref masterTotal, taskLocalTotal); 
      }); 


public class ParallelLoopState{ 
   public void Stop(); 
   public Boolean IsStopped { get; } 

   public void Break(); 
   public Int64? LowestBreakIteration{ get; } 

   public Boolean IsExceptional { get; } 
   public Boolean ShouldExitCurrentIteration { get; } 
}


public struct ParallelLoopResult { 
   // Returns false if the operation was ended prematurely 
   public Boolean IsCompleted { get; } 
   public Int64? LowestBreakIteration{ get; } 
}

Parallel Language Integrated Query

private static void ObsoleteMethods(Assembly assembly) { 
   var query = 
      from type in assembly.GetExportedTypes().AsParallel() 

      from method in type.GetMethods(BindingFlags.Public |  
         BindingFlags.Instance | BindingFlags.Static) 

      let obsoleteAttrType = typeof(ObsoleteAttribute) 

      where Attribute.IsDefined(method, obsoleteAttrType) 

      orderby type.FullName 

      let obsoleteAttrObj = (ObsoleteAttribute)  
         Attribute.GetCustomAttribute(method, obsoleteAttrType) 

      select String.Format("Type={0}\nMethod={1}\nMessage={2}\n", 
            type.FullName, method.ToString(), obsoleteAttrObj.Message); 

   // Display the results 
   foreach (var result in query) Console.WriteLine(result); 
   // query.ForAll(Console.WriteLine);
}

System.Threading.Timer

public sealed class Timer : MarshalByRefObject, IDisposable {  
   public Timer(TimerCallback callback, Object state, Int32    dueTime, Int32    period);    
   public Timer(TimerCallback callback, Object state, UInt32   dueTime, UInt32   period);  
   public Timer(TimerCallback callback, Object state, Int64    dueTime, Int64    period);   
   public Timer(TimerCallback callback, Object state, Timespan dueTime, TimeSpan period);  
}

public sealed class Timer : MarshalByRefObject, IDisposable {  
   public Boolean Change(Int32    dueTime, Int32    period);  
   public Boolean Change(UInt32   dueTime, UInt32   period);  
   public Boolean Change(Int64    dueTime, Int64    period);  
   public Boolean Change(TimeSpan dueTime, TimeSpan period);   
}

internal static class TimerDemo { 
   private static Timer s_timer; 

   public static void Main() { 
      Console.WriteLine("Checking status every 2 seconds"); 

      // Create the Timer ensuring that it never fires. This ensures that 
      // s_timer refers to it BEFORE Status is invoked by a thread pool thread 
      s_timer = new Timer(Status, null, Timeout.Infinite, Timeout.Infinite); 

      // Now that s_timer is assigned to, we can let the timer fire knowing 
      // that calling Change in Status will not throw a NullReferenceException 
      s_timer.Change(0, Timeout.Infinite); 

      Console.ReadLine();   // Prevent the process from terminating 
   } 

   // This method's signature must match the TimerCallback delegate 
   private static void Status(Object state) { 
      // This method is executed by a thread pool thread 
      Console.WriteLine("In Status at {0}", DateTime.Now); 
      Thread.Sleep(1000);  // Simulates other work (1 second) 

      // Just before returning, have the Timer fire again in 2 seconds 
      s_timer.Change(2000, Timeout.Infinite); 

      // When this method returns, the thread goes back 
      // to the pool and waits for another work item 
   } 
}

internal static class DelayDemo { 
   public static void Main() { 
      Console.WriteLine("Checking status every 2 seconds"); 
      Status(); 
      Console.ReadLine();   // Prevent the process from terminating 
   } 

   // This method can take whatever parameters you desire 
   private static async void Status() { 
      while (true) { 
         Console.WriteLine("Checking status at {0}", DateTime.Now); 
         // Put code to check status here... 

         // At end of loop, delay 2 seconds without blocking a thread 
         await Task.Delay(2000); // await allows thread to return 
         // After 2 seconds, some thread will continue after await to loop around 
      } 
   } 
}

I/O Async

private static async Task<String> IssueClientRequestAsync(String serverName, String message) { 
   using (var pipe = new NamedPipeClientStream(serverName, "PipeName", PipeDirection.InOut,  
      PipeOptions.Asynchronous | PipeOptions.WriteThrough)) { 

      pipe.Connect(); // Must Connect before setting ReadMode 
      pipe.ReadMode = PipeTransmissionMode.Message; 

      // Asynchronously send data to the server 
      Byte[] request = Encoding.UTF8.GetBytes(message); 
      await pipe.WriteAsync(request, 0, request.Length); 
       // Asynchronously read the server's response 
      Byte[] response = new Byte[1000]; 
      Int32 bytesRead = await pipe.ReadAsync(response, 0, response.Length); 
      return Encoding.UTF8.GetString(response, 0, bytesRead); 
   }  // Close the pipe 
}

Using Async with other methods

public static class TaskLogger { 
   public enum TaskLogLevel { None, Pending } 
   public static TaskLogLevel LogLevel { get; set; } 

   public sealed class TaskLogEntry { 
      public Task Task { get; internal set; } 
      public String Tag { get; internal set; } 
      public DateTime LogTime { get; internal set; } 
      public String CallerMemberName { get; internal set; } 
      public String CallerFilePath { get; internal set; } 
      public Int32 CallerLineNumber { get; internal set; } 
      public override string ToString() { 
         return String.Format("LogTime={0}, Tag={1}, Member={2}, File={3}({4})", 
            LogTime, Tag ?? "(none)", CallerMemberName, CallerFilePath, CallerLineNumber); 
      } 
   } 


   private static readonly ConcurrentDictionary<Task, TaskLogEntry> s_log =  
      new ConcurrentDictionary<Task, TaskLogEntry>(); 
   public static IEnumerable<TaskLogEntry> GetLogEntries() { return s_log.Values; } 

   public static Task<TResult> Log<TResult>(this Task<TResult> task, String tag = null, 
      [CallerMemberName] String callerMemberName = null, 
      [CallerFilePath] String callerFilePath = null, 
      [CallerLineNumber] Int32 callerLineNumber = ­1) { 
      return (Task<TResult>) 
         Log((Task)task, tag, callerMemberName, callerFilePath, callerLineNumber); 
   } 

   public static Task Log(this Task task, String tag = null, 
      [CallerMemberName] String callerMemberName = null, 
      [CallerFilePath] String callerFilePath = null, 
      [CallerLineNumber] Int32 callerLineNumber = ­1) { 
      if (LogLevel == TaskLogLevel.None) return task; 
      var logEntry = new TaskLogEntry { 
         Task = task, 
         LogTime = DateTime.Now, 
         Tag = tag, 
         CallerMemberName = callerMemberName, 
         CallerFilePath = callerFilePath, 
         CallerLineNumber = callerLineNumber 
      }; 
      s_log[task] = logEntry; 
      task.ContinueWith(t => { TaskLogEntry entry; s_log.TryRemove(t, out entry); }, 
         TaskContinuationOptions.ExecuteSynchronously); 
      return task; 
   } 
}

public static async Task Go() { 
#if DEBUG 
   // Using TaskLogger incurs a memory and performance hit; so turn it on in debug bui
   TaskLogger.LogLevel = TaskLogger.TaskLogLevel.Pending; 
#endif 

   // Initiate 3 task; for testing the TaskLogger, we control their duration explicitl
   var tasks = new List<Task> { 
      Task.Delay(2000).Log("2s op"), 
      Task.Delay(5000).Log("5s op"), 
      Task.Delay(6000).Log("6s op") 
   }; 

   try { 
      // Wait for all tasks but cancel after 3 seconds; only 1 task should complete in time 
      // Note: WithCancellation is my extension method described later in this chapter 
      await Task.WhenAll(tasks). 
         WithCancellation(new CancellationTokenSource(3000).Token); 
   } 
   catch (OperationCanceledException) { } 

   // Ask the logger which tasks have not yet completed and sort 
   // them in order from the one that’s been waiting the longest 
   foreach (var op in TaskLogger.GetLogEntries().OrderBy(tle => tle.LogTime)) 
      Console.WriteLine(op); 
}

private static async void StartServer() { 
   while (true) { 
      var pipe = new NamedPipeServerStream(c_pipeName, PipeDirection.InOut, ­1, 
         PipeTransmissionMode.Message, PipeOptions.Asynchronous | PipeOptions.WriteThrough); 

      // Asynchronously accept a client connection 
      // NOTE: NamedPipServerStream uses the old Asynchronous Programming Model (APM)  
      // I convert the old APM to the new Task model via TaskFactory's FromAsync method 
      await Task.Factory.FromAsync(pipe.BeginWaitForConnection, pipe.EndWaitForConnection,  
         null); 

      // Start servicing the client, which returns immediately because it is asynchronous 
      ServiceClientRequestAsync(pipe); 
   } 
}

Wrapping old APi to Async

private static async Task<String> AwaitWebClient(Uri uri) { 
   // The System.Net.WebClient class supports the Event­based Asynchronous Pattern 
   var wc = new System.Net.WebClient(); 

   // Create the TaskCompletionSource and its underlying Task object 
   var tcs = new TaskCompletionSource<String>(); 

   // When a string completes downloading, the WebClient object raises the 
   // DownloadStringCompleted event, which completes the TaskCompletionSource 
   wc.DownloadStringCompleted += (s, e) => { 
      if (e.Cancelled) tcs.SetCanceled(); 
      else if (e.Error != null) tcs.SetException(e.Error); 
      else tcs.SetResult(e.Result); 
   }; 

   // Start the asynchronous operation 
   wc.DownloadStringAsync(uri); 

   // Now, we can the TaskCompletionSource’s Task and process the result as usual 
   String result = await tcs.Task; 
   // Process the resulting string (if desired)... 

   return result; 
}

Async lambda

// Task.Run is called on the GUI thread 
Task.Run(async () => { 
   // This code runs on a thread pool thread 
   // TODO: Do intensive compute­bound processing here... 

   await XxxAsync();  // Initiate asynchronous operation 
   // Do more processing here... 
});



public static async Task Go() { 
   // Start the server, which returns immediately because  
   // it asynchronously waits for client requests 
   StartServer(); // This returns void, so compiler warning to deal with 

   // Make lots of async client requests; save each client's Task<String> 
   List<Task<String>> requests = new List<Task<String>>(10000); 
   for (Int32 n = 0; n < requests.Capacity; n++) 
      requests.Add(IssueClientRequestAsync("localhost", "Request #" + n)); 

   // Asynchronously wait until all client requests have completed 
   // NOTE: If 1+ tasks throws, WhenAll rethrows the last­throw exception 
   String[] responses = await Task.WhenAll(requests); 

   // Process all the responses 
   for (Int32 n = 0; n < responses.Length; n++) 
      Console.WriteLine(responses[n]); 
}

public static async Task Go() { 
   // Start the server, which returns immediately because  
   // it asynchronously waits for client requests 
   StartServer(); 

   // Make lots of async client requests; save each client's Task<String> 
   List<Task<String>> requests = new List<Task<String>>(10000); 
   for (Int32 n = 0; n < requests.Capacity; n++) 
      requests.Add(IssueClientRequestAsync("localhost", "Request #" + n));   
   // Continue AS EACH task completes 
   while (requests.Count > 0) { 
      // Process each completed response sequentially 
      Task<String> response = await Task.WhenAny(requests); 
      requests.Remove(response);  // Remove the completed task from the collection 

      // Process a single client's response 
      Console.WriteLine(response.Result); 
   } 
}

System.Threading.SynchronizationContext

how avoid deadlock
private async Task<String> GetHttp() { 
   // Issue the HTTP request and let the thread return from GetHttp 
   HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/") 
      .ConfigureAwait(false); 
   // We DO get here now because a thread pool can execute this code  
   // as opposed to forcing the GUI thread to execute it.       

   return await msg.Content.ReadAsStringAsync().ConfigureAwait(false); 
}

private Task<String> GetHttp() { 
   return Task.Run(async () => { 
      // We run on a thread pool thread now that has no SynchronizationContext on it 
      HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/"); 
      // We DO get here because some thread pool can execute this code       

      return await msg.Content.ReadAsStringAsync(); 
   }); 
}

Storage.StorageFile.OpenAsync()

FileStream

 FileOptions.Asynchronous 

I/O Request Priorities

Thread Synchronization

Make all your static methods thread safe and make all your instance methods not thread safe.
If the purpose of the instance method is to coordinate threads, then the instance method should be thread safe.

User-Mode Constructs

System.Threading.Volatile
public static class Volatile { 
   public static void  Write(ref Int32 location, Int32 value);  
   public static Int32 Read(ref Int32 location);  
}

write the last value by calling Volatile.Write and read the first value by calling Volatile.Read


internal sealed class ThreadsSharingData { 
    private Int32 m_flag = 0; 
    private Int32 m_value = 0; 

    // This method is executed by one thread  
    public void Thread1() { 
        // Note: 5 must be written to m_value before 1 is written to m_flag 
        m_value = 5; 
        Volatile.Write(ref m_flag, 1); 
    } 

    // This method is executed by another thread  
    public void Thread2() { 
        // Note: m_value must be read after m_flag is read  
        if (Volatile.Read(ref m_flag) == 1)  
            Console.WriteLine(m_value); 
    } 
}
volatile keyword
internal sealed class ThreadsSharingData { 
   private volatile Int32 m_flag = 0; 
   private          Int32 m_value = 0; 

   // This method is executed by one thread  
   public void Thread1() { 
      // Note: 5 must be written to m_value before 1 is written to m_flag 
      m_value = 5; 
      m_flag = 1; 
   } 

   // This method is executed by another thread  
   public void Thread2() { 
      // Note: m_value must be read after m_flag is read  
      if (m_flag == 1) 
         Console.WriteLine(m_value); 
   } 
}
System.Threading.Interlocked
public static class Interlocked {  
   // return (++location)  
   public static Int32 Increment(ref Int32 location);  

   // return (­­location)  
   public static Int32 Decrement(ref Int32 location);  

   // return (location += value)  
   // Note: value can be a negative number allowing subtraction  
   public static Int32 Add(ref Int32 location, Int32 value);  

   // Int32 old = location; location = value; return old;  
   public static Int32 Exchange(ref Int32 location, Int32 value);  

   // Int32 old = location;  
   // if (location == comparand) location = value; 
   // return old;  
   public static Int32 CompareExchange(ref Int32 location, Int32 value, Int32 comparand);  
   ...  
}


internal sealed class MultiWebRequests { 
   // This helper class coordinates all the asynchronous operations 
   private AsyncCoordinator m_ac = new AsyncCoordinator(); 

   // Set of web servers we want to query & their responses (Exception or Int32) 
   // NOTE: Even though multiple could access this dictionary simultaneously, 
   // there is no need to synchronize access to it because the keys are  
   // read­only after construction 
   private Dictionary<String, Object> m_servers = new Dictionary<String, Object> { 
      { "http://Wintellect.com/", null }, 
      { "http://Microsoft.com/",  null }, 
      { "http://1.1.1.1/",        null }  
   }; 

   public MultiWebRequests(Int32 timeout = Timeout.Infinite) { 
      // Asynchronously initiate all the requests all at once 
      var httpClient = new HttpClient(); 
      foreach (var server in m_servers.Keys) { 
         m_ac.AboutToBegin(1); 
         httpClient.GetByteArrayAsync(server) 
            .ContinueWith(task => ComputeResult(server, task)); 
      } 

      // Tell AsyncCoordinator that all operations have been initiated and to call 
      // AllDone when all operations complete, Cancel is called, or the timeout occurs 
      m_ac.AllBegun(AllDone, timeout); 
   } 

   private void ComputeResult(String server, Task<Byte[]> task) { 
      Object result; 
      if (task.Exception != null) { 
         result = task.Exception.InnerException; 
      } else { 
         // Process I/O completion here on thread pool thread(s) 
         // Put your own compute­intensive algorithm here... 
         result = task.Result.Length;   // This example just returns the length 
      } 
       // Save result (exception/sum) and indicate that 1 operation completed 
      m_servers[server] = result; 
      m_ac.JustEnded(); 
   } 

   // Calling this method indicates that the results don't matter anymore 
   public void Cancel() { m_ac.Cancel(); } 

   // This method is called after all web servers respond,  
   // Cancel is called, or the timeout occurs 
   private void AllDone(CoordinationStatus status) { 
      switch (status) { 
         case CoordinationStatus.Cancel: 
            Console.WriteLine("Operation canceled."); 
            break; 

         case CoordinationStatus.Timeout: 
            Console.WriteLine("Operation timed­out."); 
            break; 

         case CoordinationStatus.AllDone: 
            Console.WriteLine("Operation completed; results below:"); 
            foreach (var server in m_servers) { 
               Console.Write("{0} ", server.Key); 
               Object result = server.Value; 
               if (result is Exception) { 
                  Console.WriteLine("failed due to {0}.", result.GetType().Name); 
               } else { 
                  Console.WriteLine("returned {0:N0} bytes.", result); 
               } 
            } 
            break; 
      } 
   } 
}


internal sealed class AsyncCoordinator { 
    private Int32 m_opCount = 1;        // Decremented when AllBegun calls JustEnded 
    private Int32 m_statusReported = 0; // 0=false, 1=true 
    private Action<CoordinationStatus> m_callback; 
    private Timer m_timer; 

    // This method MUST be called BEFORE initiating an operation  
    public void AboutToBegin(Int32 opsToAdd = 1) {  
      Interlocked.Add(ref m_opCount, opsToAdd);  
    } 

    // This method MUST be called AFTER an operation’s result has been processed  
    public void JustEnded() { 
      if (Interlocked.Decrement(ref m_opCount) == 0)  
         ReportStatus(CoordinationStatus.AllDone); 
    } 

    // This method MUST be called AFTER initiating ALL operations 
    public void AllBegun(Action<CoordinationStatus> callback,  
      Int32 timeout = Timeout.Infinite) { 
      m_callback = callback; 
      if (timeout != Timeout.Infinite) 
         m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite); 
      JustEnded(); 
    } 

    private void TimeExpired(Object o) { ReportStatus(CoordinationStatus.Timeout); } 
    public void Cancel()               { ReportStatus(CoordinationStatus.Cancel); } 

    private void ReportStatus(CoordinationStatus status) { 
      // If status has never been reported, report it; else ignore it 
      if (Interlocked.Exchange(ref m_statusReported, 1) == 0)  
         m_callback(status); 
    } 
}
Simple Spin Lock
System.Threading.SpinWait
System.Threading.SpinLock

Thread
public static void Sleep(Int32 millisecondsTim
public static void Sleep(TimeSpan timeout);
public static Boolean Yield();
public static void SpinWait(Int32 iterations);


internal struct SimpleSpinLock { 
    private Int32 m_ResourceInUse; // 0=false (default), 1=true 

    public void Enter() { 
      while (true) { 
         // Always set resource to in­use 
         // When this thread changes it from not in­use, return 
         if (Interlocked.Exchange(ref m_ResourceInUse, 1) == 0) return; 
         // Black magic goes here... 
      } 
    } 

    public void Leave() { 
      // Set resource to not in­use 
      Volatile.Write(ref m_ResourceInUse, 0); 
    } 
}

public sealed class SomeResource { 
    private SimpleSpinLock m_sl = new SimpleSpinLock(); 

    public void AccessResource() { 
      m_sl.Enter(); 
      // Only one thread at a time can get in here to access the resource... 
      m_sl.Leave(); 
    } 
}
Interlocked Anything Pattern
public static Int32 Maximum(ref Int32 target, Int32 value) { 
   Int32 currentVal = target, startVal, desiredVal; 

   // Don't access target in the loop except in an attempt  
   // to change it because another thread may be touching it  
   do { 
      // Record this iteration's starting value 
      startVal = currentVal; 

      // Calculate the desired value in terms of startVal and value 
      desiredVal = Math.Max(startVal, value); 

      // NOTE: the thread could be preempted here! 

      // if (target == startVal) target = desiredVal 
      // Value prior to potential change is returned 
      currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); 

      // If the starting value changed during this iteration, repeat  
   } while (startVal != currentVal); 

   // Return the maximum value when this thread tried to set it 
   return desiredVal; 
}


delegate Int32 Morpher<TResult, TArgument>(Int32 startValue, TArgument argument,  
   out TResult morphResult); 

static TResult Morph<TResult, TArgument>(ref Int32 target, TArgument argument,  
   Morpher<TResult, TArgument> morpher) { 

   TResult morphResult; 
   Int32 currentVal = target, startVal, desiredVal; 
   do { 
      startVal = currentVal; 
      desiredVal = morpher(startVal, argument, out morphResult); 
      currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); 
   } while (startVal != currentVal); 
   return morphResult; 
}

Kernel-Mode Constructs

  • Events
  • Semaphores
    – Mutex

System.Threading
.WaitHandle

  .EventWaitHandle 
     .AutoResetEvent 
     .ManualResetEvent
  .Semaphore 
  .Mutex

public abstract class WaitHandle : MarshalByRefObject, IDisposable { 
   // WaitOne internally calls the Win32 WaitForSingleObjectEx function.  
   public virtual Boolean WaitOne(); 
   public virtual Boolean WaitOne(Int32 millisecondsTimeout); 
   public virtual Boolean WaitOne(TimeSpan timeout); 

   // WaitAll internally calls the Win32 WaitForMultipleObjectsEx function  
   public static Boolean WaitAll(WaitHandle[] waitHandles); 
   public static Boolean WaitAll(WaitHandle[] waitHandles, Int32 millisecondsTimeout); 
   public static Boolean WaitAll(WaitHandle[] waitHandles, TimeSpan timeout); 

   // WaitAny internally calls the Win32 WaitForMultipleObjectsEx function  
   public static Int32 WaitAny(WaitHandle[] waitHandles); 
   public static Int32 WaitAny(WaitHandle[] waitHandles, Int32 millisecondsTimeout);   public 
static Int32 WaitAny(WaitHandle[] waitHandles, TimeSpan timeout); 
   public const Int32 WaitTimeout = 258; // Returned from WaitAny if a timeout occurs 

   //  Dispose internally calls the Win32 CloseHandle function – DON’T CALL THIS. 
   public void Dispose(); 

}


using System; 
using System.Threading; 

public static class Program { 
   public static void Main() { 
      Boolean createdNew; 

      // Try to create a kernel object with the specified name 
      using (new Semaphore(0, 1, "SomeUniqueStringIdentifyingMyApp", out createdNew)) { 
         if (createdNew) { 
            // This thread created the kernel object so no other instance of this 
            // application must be running. Run the rest of the application here... 
         } else { 
            // This thread opened an existing kernel object with the same string name; 
            // another instance of this application must be running now. 
            // There is nothing to do in here, let's just return from Main to terminate 
            // this second instance of the application. 
         } 
      } 
   } 
}

System.ComponentModel.DataAnnotations

INotifyPropertyChanged

ObservableCollection

coded ui tests

timers

hotkeys

http://greatis.com/dotnet/nostalgia/hotkeys.html
http://stackoverflow.com/questions/4377565/setting-application-wide-hotkey-in-c-sharp
http://stackoverflow.com/questions/400113/best-way-to-implement-keyboard-shortcuts-in-a-windows-forms-application
http://stackoverflow.com/questions/48935/how-can-i-register-a-global-hot-key-to-say-ctrlshiftletter-using-wpf-and-ne
http://bloggablea.wordpress.com/2007/05/01/global-hotkeys-with-net/
http://stackoverflow.com/questions/81150/best-way-to-tackle-global-hotkey-processing-in-c


Back to posts


comments powered by Disqus