Loading blog entries.. loading


Blogs which referenced tag: [.Net]

 

Atomic Operation in C#.Net

 
Written by Wayne Ye  Tuesday, October 25, 2011

Introduction

Atomic Operation is named academic to Linearizability, Atomicity is a guarantee of isolation from concurrent processes, it can be enfored by hardware level build on Cache Coherence protocol, or software level exclusive lock. In this blog post, I am going to explore a few number of mechanisms to achieve atomic operation in .Net.

What are Atomic operations and what are not?

In C# Specification, the stamement about atomic operation is:

“Reads and writes of the following data types shall be atomic: bool, char, byte, sbyte, short, ushort, uint, int, float, and reference types.” Also: “…there is no guarantee of atomic read-modify-write, such as in the case of increment or decrement.”.

Threading In C# by Joseph Albahari described:

"Read/write on a field of 32-bit or less is always atomic, operations on 64-bit are guaranteed to be atomic only in 64-bit OS, statements that combine more than one read/write operation are never atomic."

For example, following operations are guaranteed to be atomic operations:

 int i = 3; // Always atomic
long l = Int64.MaxValue; // Atomic in 64-bit enviroment, non-atomic on 32-bit environment

Code like below are never atomic:

 int i = 0;
int j += i// Non-atomic, read and write operation
i++;         // Non-atomic, read and write operation

And I am trying to document atomic operation in a lower level in the section below.

Essence

Comsidering two threads (or two processes) are running simultaneously: T1 and T2, there is a field stored in memory, T1 reads its value and do some calculation on the value and finally write the new value back to memory, during the period T2 was actually doing exact same task - i.e. read/calculate/write value back, so possibly one operation on this field overrides another - in other word: the later executed thread (T2) might override the earlier executed one (T1) because when it read the field's value another thread was just manipulating on it, and after T1 finished writing the new value back to memory, T2 writes back.

So a simple example is the increament/decrement operation, as I showed above, it is NOT an atomic operation, it requires both read and write, if many thread simultaneously doing increment on one field, it will very possible cause race condition (the more threads, the more increment operation going to do, the more possibility race condition happen).

Atomicity example

I wrote a Winform application, it do simple work:

Create 10 threads at runtime and simultaneously operates on a private interger, there is a volatile counter with initial value 0, every thread finishes its work will:

  1. Print information on UI.
  2. Increment the counter
  3. Check whether the counter reachs 10, if yes, print CalculatingFinished method which will print the final result.

And I wish UI won't block during the calculation, otherwise I can simply join every created thread. My code skeleton is showing below:

 private const int MaxThraedCount = 10;
private Thread[] m_Workers = new Thread[MaxThraedCount];
private volatile int m_Counter = 0;
private Int32 x = 0;

protected void btn_DoWork_Click(object sender, EventArgs e)
{
    ShowStatus("Starting...");

    for (int i = 0; i < MaxThraedCount; i++)
    {
        m_Workers[i] = new Thread(IncreaseNumber) { Name = "Thread " + (i + 1) };
        m_Workers[i].Start();
    }
}

void IncreaseNumber()
{
    try
    {
        for (int i = 0; i < 10000; i++)
        {
            // Different strategy to increment x
        }

        ShowStatus(String.Format("{0} finished at {1}", Thread.CurrentThread.Name, m_Watcher.Elapsed.TotalMilliseconds));
       
        // Increases Counter and decides whether or not sets the finish signal
        m_Counter++;
        if (m_Counter == MaxThraedCount)
        {
            // Print finish information on UI
            CalculatingFinished();
            m_Counter = 0;
        }
    }
    catch (Exception ex)
    {
        throw;
    }
}

public void ShowStatus(string info)
{
    this.InvokeAction(() => listInfo.Items.Add(info));
}

private void CalculatingFinished()
{
    ShowStatus("\r\nAll Done at: " + m_Watcher.Elapsed.TotalMilliseconds);
    ShowStatus("The result: " + x.ToString());
}

I highlighted "// Different strategy to increment x", and will try a few number of ways to achieve atomicity using FCL libriries.

Let's first see the non-atomic routine - simple do x++ in each thread: 

 for (int i = 0; i < 10000; i++)
{
    x++;
}

Since x++ is NOT atomicity, in additional, I made a large loop - 10 thousand times, in my experience, I NEVER get the correct result, the screenshot is below:

Non-Atomic Operation

Analysis and solutions

To solve the issue and ensure atomicity, by more than 2 weeks brokenly study I found the following feasible ways (in theory, not considering performance):

  1. Interlocked.Increment
  2. Apply exclusive lock (or Moniter.Enter) outside the for loop.
  3. AutoResetEvent to ensure threads doing task one by one. 
  4. Create a temp integer in each thread and once finish add temp onto x under an exclusive lock.
  5. ReaderWriterLockSlim.
  6. Parallel.For coordinate with Interlocked.Increment. 

All of above can achieve atomic operation on incresing x's value, and got expected result:

Atomic operation

In fact I did try other ways such as using MemoryBarrier, Thread.VolatileRead/VolatileWrite - StackOverFlow question link, but failed, if dear readers know there is way to use them to achieve the goal please kindly guide me.  

Demonstration code

In this section I will listed key code for implementing the 5 solutions above.

Solution #1: Interlocked.Increment

 for (int i = 0; i < 10000; i++)
    Interlocked.Increment(ref x);

Solution #2: Apply exclusive lock (Moniter) outside the for loop.

 private readonly string m_Locker = "THREAD_LOCKER";

Monitor.Enter(m_Locker);
for (int i = 0; i < 10000; i++)
    x++;
Monitor.Exit(m_Locker);

Solution #3: AutoResetEvent to ensure threads doing task one by one.

 private static AutoResetEvent m_AutoReset = new AutoResetEvent(false);

protected void btn_DoWork_Click(object sender, EventArgs e)
{
    ShowStatus("Starting...");

    for (int i = 0; i < MaxThraedCount; i++)
    {
        m_Workers[i] = new Thread(IncreaseNumber) { Name = "Thread " + (i + 1) };
        m_Workers[i].Start();
    }
   
    m_AutoReset.Set();
}

void IncreaseNumber()
{
    m_AutoReset.WaitOne();
    for (int i = 0; i < 10000; i++)
        x++;
    m_AutoReset.Set();
}

One notable point is in this case (UI non-blocking) it is not easy to use Monitor.Enter/Monitor.Pulse pair to replace AutoResetEvent and implement "one by one" logic becasue Monitor.Pulse won't maitain state, below is the description in MSDN:

Important

The Monitor class does not maintain state indicating that the Pulse method has been called. Thus, if you call Pulse when no threads are waiting, the next thread that calls Wait blocks as if Pulse had never been called. If two threads are using Pulse and Wait to interact, this could result in a deadlock. Contrast this with the behavior of the AutoResetEvent class: If you signal an AutoResetEvent by calling its Set method, and there are no threads waiting, the AutoResetEvent remains in a signaled state until a thread calls WaitOneWaitAny, or WaitAll. The AutoResetEvent releases that thread and returns to the unsignaled state.


In my Winform application, if I call Monitor.Pulse() in button click event, many threads will not receive the signal (whereas AutoResetEvent will remain signaled state)! I wrote a simple routine to demonstrate this:
 private static readonly string _locker = "THREAD_LOCKER";
public static void Main()
{
    for(int i = 0;i<5;i++)
    {
        Thread t = new Thread(DoWork);
        t.Name = "T" + (i + 1);
        t.IsBackground = true;
        t.Start();
    }
   
    //Thread.Sleep(500);
   
    Monitor.Enter(_locker);
    Console.WriteLine("Main thread");
    Monitor.Pulse(_locker);
    Monitor.Exit(_locker);
}

private static void DoWork()
{
    Monitor.Enter(_locker);
    Monitor.Wait(_locker);
    Monitor.Pulse(_locker);
    Monitor.Exit(_locker);
    Console.WriteLine(Thread.CurrentThread.Name + " finished and exist");
}
Removing "Thread.Sleep(500)" will *VERY POSSIBLY* lead less than 5 thread working, because creating 5 threads requires not short time (kenel object, TEB, kenel/user stack), during the period one just created thread (T2) might get the signal or might not (much more possible), because when the previously created thread (T1) calling "Monitor.Pulse(_locker)" T2 had NOT been setup, T2 and the thread created later will have no chance to get signal! They will be waiting... So the 0.5 seconds is used to give time to create 5 thread, otherwise main thread will quit immediately and background thread will be collected.

Solution #4: Create a temp integer in each thread and once finish add temp onto x under a exclusive lock.

 private readonly string m_Locker = "THREAD_LOCKER";

void IncreaseNumber(object objThreadName)
{
    int tmp = 0;
    for (int i = 0; i < 10000; i++)
        tmp++;

    lock (m_Locker)
        x += tmp;
}

Solution #5: ReaderWriterLockSlim.

 void IncreaseNumber(object objThreadName)
{
    // Or we can use ReaderWriterLock.AcquireWriterLock(500) but it has more performance overhead and is not recommended
    m_ReaderWriterLocker.EnterWriteLock();
    for (int i = 0; i < 10000; i++)
        x++;
    m_ReaderWriterLocker.ExitWriteLock();  // Or ReaderWriterLock.ReleaseWriterLock();
}

Please note that ReaderWriterLock class is not recommended, it "take about five times longer to execute than a call to Monitor's Enter method." please refer: Reader/Writer Locks and the ResourceLock Library by Jeffery Richter.

Solution #6: Parallel.Forcoordinate with Interlocked.Increment.

 Parallel.For(0, 100000, (i) => Interlocked.Increment(ref x));

Conclusion

In this post I took a simple & straight-forward example: 10 threads simultaneously operating on on field, to experiment atomicity operation in C#.Net, using synchronization technology including exclusive locking, signaling, non-blocking synchronization, I guess this is a very good example to master basic FCL thread libraries/concepts such as Interlocked, Monitor, MemoryBarrier, volatile, AutoResetEvent, ReaderWriterLockSlim, etc.

Multi-threading programming is indeed very complex, during my investigation I happened to saw even Jon Skeet admitted he had “his eyes opened to the precise meaning of volatile which isn't "always read from main memory, always write directly to main memory" (link), so as a rookie in this field I should invest more effort on it:)

Further Reading

Threading In C# (Strongly recommended!!!)

Linearizability Wikipedia

Introducing the new ReaderWriterLockSlim in Orcas

Asynchronous Code Blocks

Atomic Operations

Boosting Performance with Atomic Operations in .NET 4


View Post»



Permalink:http://wayneye.com/Blog/Atomic-Operation-In-Csharp
Tag:

Exception handling particulars in C#

 
Written by Wayne Ye  Friday, July 8, 2011

Background

Exception handling appears in most .NET applications, this post is trying to describe some  Exception handling particulars in C# which might not take enough awareness from C# developers. 

Differences between throw and throw ex 

I guess every C# developer has seen code snippet below:

 try
{
    // Do some work, exception occurs
}
catch (IOException ex)
{
    // Exception caught, re-throw it to bubble up
    throw ex;
}

In the catch block, we can rethrow the caught exception instance of IOException to higher level, and we may also saw another way in a little different:

 try
{
    // Do some work, exception occurs
}
catch (IOException ex)
{
    // Exception caught, re-throw it to bubble up
    throw;
}

Is there any different? 

The answer is yes! To prove that I wrote a simple snippet of code below, first is a simple customized Exception: DummyException.

 internal class DummyException : Exception
{
    public DummyException(String dummymsg)
        : base(dummymsg)
    {

    }

    public DummyException(String dummymsg, Exception innerException)
        : base(dummymsg, innerException)
    {

    }
}

 And then I manually throw the DummyException within one method, while handle it in different way mentioned above:

 class Program
{
    private static void DoLowLevelOperation()
    {
        // Do some low level operation
        throw new DummyException("A dummy exception message!");
    }

    public static void MethodThrowException1()
    {
        try
        {
            DoLowLevelOperation();
        }
        catch (DummyException de)
        {
            throw;
        }
    }
    public static void MethodThrowException2()
    {
        try
        {
            DoLowLevelOperation();
        }
        catch (DummyException de)
        {
            throw de;
        }
    }

    static void Main(string[] args)
    {
        try
        {
            MethodThrowException1();
        }
        catch (DummyException de1)
        {
            Console.WriteLine(de1.Message);
            Console.WriteLine(de1.StackTrace);
        }

        try
        {
            MethodThrowException2();
        }
        catch (DummyException de2)
        {
            Console.WriteLine(de2.Message);
            Console.WriteLine(de2.StackTrace);
        }
    }
}

 The result will be:


View Post»



Permalink:http://wayneye.com/Blog/Exception-Handling-Particulars-In-Csharp
Tag:

Utilize gzip compression in IIS

 
Written by Wayne Ye  Friday, December 10, 2010

GZIP format is developed by GNU Project and standardized by IETF in RFC 1952, which MUST be considered by web developers to improve their websites' performance, there are several Quintessential articles documented using gzip compression, they are:


10 Tips for Writing High-Performance Web Applications
Best Practices for Speeding Up Your Web Site
How To Optimize Your Site With GZIP Compression
IIS 7 Compression. Good? Bad? How much?

A gzip compressed HTTP package can significantly save bandwidth thus speed up browser rendering after use hitting enter, so that user experience got improved finally, nowadays most of the popular browsers such as IE, Firefox, Chrome, Opera support gzip encoded content (please refer: http://en.wikipedia.org/wiki/HTTP_compression).

PS: the other compression encoding is deflate, "but it's less effective and less popular" (refer: http://developer.yahoo.com/performance/rules.html). Yahoo uses gzip compression and suggest developers do that:

 

Compression in IIS

For ASP.NET developer who host website


View Post»



Permalink:http://wayneye.com/Blog/IIS-Gzip-Compression
Tag:

A complete Impersonation Demo in C#.NET

 
Written by Wayne Ye  Friday, October 22, 2010

Under some scenarios we need impersonate another Windows account and do some work under that user’s session, for example:

  • An enterprise ASP.NET web application provides server administrators’ ability to access the server under some specific privilege set; Server admin input their NT account information (domain\account + password) on the page, we need get WinNT Access Token and then impersonate this server user, so that we acquire its specific privilege and do the things ONLY THIS ACCOUNT CAN DO.
  • We developed a Windows Service which needs internet access periodically, but a specific user sets an Sock5 proxy to access internet, then your Windows Service needs to know the Socks proxy information so that it could access internet, you must impersonate this user and read the settings.

Impersonation definition

Definition copied from: http://msdn.microsoft.com/en-us/library/aa376391(VS.85).aspx

Impersonation is the ability of a thread to execute using different security information than the process that owns the thread. Typically, a thread in a server application impersonates a client. This allows the server thread to act on behalf of that client to access objects on the server or validate access to the client’s own objects.

I read many articles and blogs and wrote an ImpersonateHelper class to do impersonation work, during the investigating I noticed that very few articles/blogs refer a complete impersonation process, so I decided to write one that refer as more details as I can, and actually my code was a code snippet combination came from 10+ sourcesSmile.

Functionality

I create a local user: TempUser which belongs to “Administrators” (make sure log on TempUser at least once), I logged on as my own account and I am going to impersonate TempUser and do two things:


View Post»



Permalink:http://wayneye.com/Blog/DotNet-Impersonation-Demo
Tag:

Encrypt .Net Configuration file

 
Written by Wayne Ye  Friday, June 11, 2010

Under some scenarios the developers want to encrypt some sections inside app.config or web.config file, this article How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA describes how to do so clearly, Scott Guthrie also posted one: Encrypting Web.Config Values in ASP.NET 2.0.

However, in the posts above they uses aspnet_regiis.exe and seems it doesn’t directly support app.config, if we want to encrypt app.config for Windows Form or WPF applications, while I tried use it to encrypt my app.config file, it generates a web.config which means my Winform definitely can’t use it, even if I copy the encrypted appSettings section from this generated web.config to my own app.config(ConfigurationManager.AppSettings[EncryptedKeyName] is null after I did that).

Config Encrypt


View Post»



Permalink:http://wayneye.com/Blog/Encrypt-DotNet-Configuration-File
Tag:

Personal Schedule Management Tool

 
Written by Wayne Ye  Wednesday, May 19, 2010

Time is always ticking no matter you care it or you don’t care it, everyone knows it including myself, to remind myself don’t waste too much time on gaming, reading news or something else, I developed a little tool which I call it “Personal Schedule Management Tool” to achieve this simple goal.

Mechanism

I create an XML file to store a serial of [time stamp/task to do] pairs, the tool will start with Windows and load the XML file, a working timer behind it will periodically check whether there is a task needs to be done at defined time stamp, once the condition is matched, the tool will

  1. Shows Windows Balloon Tips with the task as content, screenshot below.
    Balloon
  2. Invokes managed Microsoft Speech API: SpeechSynthesizer.Speak() to remind me even if I am not in front of my dev-box at that time.

Here is my XML to store schedule items:

<?xml version="1.0" encoding="utf-8" ?>
<WayneScheduleItems>
  <ScheduleItem TriggerHour="18" TriggerMinute="20" Content="Wayne, time to have your dinner." />
  <ScheduleItem TriggerHour="19" TriggerMinute="0" Content="Wayne! It is time to learn technologies and programming skills, i.e. CODING TIME!" />
  <ScheduleItem TriggerHour="20" TriggerMinute="30" Content="OK, your eye and brain need rest, time to do some body execise - running, sit-ups, push-up, etc.  Enjoy:)" />
  <ScheduleItem TriggerHour="21" TriggerMinute="0" Content="Well, sweat off your face and have a bath:)." />
  <ScheduleItem TriggerHour="21" TriggerMinute="30" Content="All right, well come back, you know you should read some books!" />
  <ScheduleItem TriggerHour="23" TriggerMinute="0" Content="Wayne, thanks for the hard work! Time to sleep, have a good night!" />
</WayneScheduleItems>


View Post»



Permalink:http://wayneye.com/Blog/Personal-Schedule-Management-Tool
Tag:

A good lesson and experience

 
Written by Wayne Ye  Thursday, September 3, 2009

I was extremely busy during the last two weeks, since our project was at bug fixing phase, my team and I worked really hard on dealing with the bugs; We fixed two to three bugs everyday by average, I am very satisfied with the efficiency myself.

During this process, I encountered several very interesting issues.

  1. There was a crash bug with P1 priority, we all cannot reproduced it until one guy from US team provided a remote server that our product always crashed, after I logged onto that server and 20 minutes investigating, I was really surprised, the reason is one line of code written by myself, it is:

    DateTime.Parse(String.Format("{0}/{1}/{2} 00:00:00 AM", DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Year))

    Does this line of code has any problem, I definitely don’t think so before, but now, I understand, it only works under English format, once non-English format, under some format such as Chinese, the AM makes non sense; and… Under some formats (such as French), the code will throw FormatException and leads program crash…

  2. Another issue is a WPF related multi-threading issue, there is a module in our product used thread pool to invoke WMI APIs to


View Post»



Permalink:http://wayneye.com/Blog/A-Good-Lesson-On-DateTime-Localization
Tag:

作息时间自动提醒Windows Service

 
Written by Wayne Ye  Friday, April 24, 2009

经济危机真真切切的影响到了几乎每一个人,09年过去三分之一多一点了,生活不太规律,确实太忙的说,工作换了,房子也换了,又做回了张江男,觉得自己再不好好努力会Out的。。。都奔三儿而去了。。。于是乎,为了勉励自己,做了这么个东东。

WSNSVC

一个Windows Service,里面跑一个Timer,每隔10秒check一下当前时间,一旦发现时间吻合,则调用Microsoft Speech Technology? 发声提醒,超级简单,不过。。。以后要么得一直戴着心爱的森海塞尔,要么只能用音箱了。。。

服务描述:
Notify Wayne to follow the schedule established by himself. If this service is disabled, Wayne may waste a lot of time...

项目层级:
SolutionHierarchy 

  • WayneScheduleService.cs Windows Service后台代码


View Post»



Permalink:http://wayneye.com/Blog/Personal-Schedule-Windows-Service
Tag: