Wednesday, August 20, 2008
Boxing & UnBoxing in C#
Does int.ToString() converts an integer (a value type) to a string (a reference type) and hence, boxes the int. On the other hand, does int.Parse() converts a string to an integer and hence, unboxes the string?
Ans: No
To find out what happens during a call to int.ToString(), I decompiled mscorlib.dll (It is present is the .NET Framework directory which on my machine happens to be C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727) which contains the implementation of Int32.
The implementation of ToString() is as follows:
public override string ToString(){
return Number.FormatInt32( this, null, NumberFormatInfo.CurrentInfo);
}
The Number.FormatInt32() method is declared as follows:
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern string FormatInt32( int value, string format, NumberFormatInfo info);
According to MSDN, the extern modifier is used in C# to declare a method that is implemented externally. So, the question is: where is FormatInt32() (see above code fragment) implemented? The answer lies in the MethodImpl attribute which decorates the method declaration. According to MSDN, MethodImplOptions.InternalCall specifies that the method is implemented in the CLR itself. So, I proceeded to download SSCLI a.k.a. Rotor (source code to a working implementation of the CLR).
I learnt that
FCFuncElement("FormatInt32", COMNumber::FormatInt32)
This tells that the implementation of FormatInt32 method is actually the implementation of the native C++ COMNumber::FormatInt32 function. So, the next question is where do I find the implementation of COMNumber::FormatInt32 function? I noticed that there was a file named comnumber.cpp in the \clr\src\vm directory. I opened the file and started to examine the COMNumber::FormatInt32 function. I discovered that COMNumber::FormatInt32 calls COMNumber::Int32ToDecChars function. This function is defined as follows:
wchar_t* COMNumber::Int32ToDecChars( wchar_t* p, unsigned int value, int digits){ LEAF_CONTRACT _ASSERTE(p != NULL);
while (--digits >= 0 value != 0) { *–p = value % 10 + ‘0′; value /= 10; } return p;}
As you can see here, COMNumber::Int32ToDecChars takes each digit of the integer starting from the rightmost digit and proceeding to the leftmost, converts it to the equivalent character and stores it in a string and returns the string. There is actually more action that goes on inside COMNumber::FormatInt32 but, I won’t be discussing that here. The core function is performed by COMNumber::Int32ToDecChars. So, I would wrap up the discussion of int.ToString() function by saying that it converts individual digits of an integer to their equivalent characters, stores them in a string and returns the string.
Next, I tried to figure out what goes on inside int.Parse(). I used .NET reflector and found out that it is pretty similar to what int.ToString() does. The string is read character-by-character, converted to its equivalent digit and added to a number after the digits converted previously have been shifted by one position.
Most C# textbooks provide an example as shown below for boxing/unboxing:
int i = 145;
object o = i; // Boxing
int j = (int)o; // Unboxing
int.ToString() and int.Parse() cannot be used in the above manner and so, these functions are not even remotely related to boxing/unboxing.
what actually happens during boxing/unboxing.
See the excerpts from Shared Source CLI Essentials:
By default, when an instance of a value type is passed from one location to another as a method parameter, it is copied in its entirety. At times, however, developers will want or need to take the value type and use it in a manner consistent with reference types. In these situations, the value type can be “boxed”: a reference type instance will be created whose data is the value type, and a reference to that instance is passed instead. Naturally, the reverse is also possible, to take the boxed value type and dereference it back into a value type - this is called “unboxing”.
The box instruction is a typesafe operation that converts a value type instance to an instance of a reference type that inherits from System.Object. It does so by making a copy of the instance and embedding it in a newly allocated object. For every value type defined, the type system defines a corresponding reference type called the boxed type. The representation of a boxed value is a location where a value of the value type may be stored; in essence, a single-field reference type whose field is that of the value type. Note that this boxed type is never visible to anyone outside the CLI’s implementation-the boxed type is silently generated by the CLI itself, and is not accessible for programmer use. (It is purely an implementation detail that would have no real utility were it exposed.)
.Net Multithreading
Multitasking: OS ability to execute multiple tasks::processes at a time. Earlier versions of windows used co-operative multitasking, where processes volunteer to release the processor. drawback-if the process doesn't release the CPU, other processes had no option but to wait endlessly. Today's OSs use pre-emptive multitasking wherein the process is involuntarily interrupted by OS and another process is executed. drawback-If 2 processes are sharig a common resource at the same time, one process may change the data, then be interrupted, allowing another process to again change the data, which can lead to issues bcs both processes assumed they had exclusive access to the data. This issue however be sorted by Synchronization.
Processes: A Process is a physically separated unit of memory & resources allocated to an application. Each process has it's own separation of data, execution code, and system resources.
Threads: An execution sequence in a process is called a thread. A thread is defined by the registers in use on CPU, memory stack used by the thread, and a container (Thread Local Storage - TLS) that keeps the track of the thread's current state.
- Every process has atleast one thread.
- A thread is really a pointer into the instruction stream portion of a process. The thread does not actually contain the instructions, but rather it indicates the current & future possible paths through the instructions determined by data and branching decisions.
Time Slices: The period that the process is allocated CPU in multitasking environment is known as Time Slice or Quantum. The period of this time slice is unknown to the programer and unpredictable.
Multithreaded processes: Initial mandatory thread in a process is called a Primary or Main thread. Further to this, we can split the process to share the time slice alloted to it. This can be done by spawning additional threads of execution within a process called - worker threads. and the concept is called Free Threading.
- Apartment Threading Model: in which each time you want to do some background work, it happens in it's own process. ... hence called out-of-process threading.
- Free Threading Model: multiple threads can spawn within a single process.
There is an even greater benefit to multithreading the applications if the computer has more than one processors.
The OS is responsible for determining which threads are executed on which processor. However, .NET platform does provide the ability to control which CPU a process uses. This is done by use of ProcessorAffinity property of the Process class in System.Diagnostics namespace. This setting is at process level and all threads of that process run on same CPU.
Interrupts: A Interrupt is a mechanism that causes the normally sequential execution of CPU instructions to branch elsewhere in the computer memory without the knowledge of the execution program. Windows determins the time slice and places an instruction in the current thread's execution sequene. The time slice can differ from system to system and even from thread to thread. Since the interrupt is placed in the instruction set, it is also known as Software Interrupt. Once the interrupt is placed, windows then allows the thread to execute. When the thread comes to the interrupt, Windows uses a special function Interrupt Handler to store the thread's state in the TLS. The current program counter ( the address of the currently executing instruction) for that thread, which was stored before the interrupt was recieved is then stored in TLS. The thread is then moved to the end of the thread queue for its given priority to wait its turn again.
- The TLS is not saved to the queue.; it is tored in the memory of the process that contains the thread. A pointer to that memory is actually saved to the queue.
- What happens when the thread decides tghat it does not need to use all of it's execution time slot? - Context Switching - A thread may decide that it needs to wait on a resource before it executes further, Therefore, it may yield its execution time to another thread. This is the responsibility of programmer and OS. The programmer signals the thread to yield. The thread then clears any interrupts that windows may have already placed in its stack. A Software interrupt is then simulated...Afterwards, it's just the same..
Thread Sleep: When a programmer takes the thread out of the thread execution queue for a specific priod of time, the thread is said to sleep. When a thread is put to sleep, it is again packed up into TLS, but this time, the TLS is placed in the Sleep queue instead of Thread execution queue. In order for a thread on sleep queue to run again, they are marked to do so with a different kind of interrupt called Clock Interrupt.
Thread Abort: Threads can be stopped explicitly as a request during the executio of another thread. When a thread is ended in this way, its called an abort. Threads also stop when they come to an end of their execution sequence. In any case, when a thread ois ended, the TLS is de-allocated.
- Threads cannot be aaborted from within themselves.
Thread Priorities:
- Scale of 0 to 31
- 0 can be only set by System and means the thread is idle.
- 1-15 can be set by users of Windows System
- >16 by administrators only.
- Threads inherit the priority of the processes in which they reside.
Lifecycle states of threads:
- Aborted
- AbortRequested
- Background
- Running
- Stopped
- StopRequested
- Suspended
- SuspendRequested
- UnStarted
- WaitSleepJoin
Few Thread class methods:
- Sleep(), Interrupt()
- Suspend(), Resume()
- Abort()
- Join()
Threading Opportunities:
- Background Processes
- Accessing External Resources
Threading Traps:
- Execution order is not fixed
- Threading in a loop can be dangerous
Working programatically with Threads:
- Creating a thread:
using System;
using System.Threading;
public class SimpleThread {
public void SimpleMethod() {
int i = 5;
int x = 10;
int result = i * x;
Console.WriteLine("This code calculated the value " + result.ToString() + " from thread ID: " + AppDomain.GetCurrentThreadId().ToString());
}
// Calling the method from our current thread
SimpleThread simpleThread = new SimpleThread();
simpleThread.SimpleMethod();
// Calling the method on a new thread
ThreadStart ts = new ThreadStart(simpleThread.SimpleMethod);
Thread t = new Thread(ts); t.Start(); Console.ReadLine();
}
}
Application Domains: