Asynchronous Programming - System.Threading.Thread - Part 2

  • Thread
  • The Thread class was, originally, a 1:1 mapping to an operating system thread.
  • It is typically used for long-running or specialized work such as monitoring a device or executing code with a low priority.
  • Using the Thread class leaves us with a lot of control over the thread.
  • Thread Class
  • The Thread class is sealed
  • Creating and Starting a Thread
  •  

Asynchronous Programming - Intro - Part 1

  • C# supports parallel execution of code through multi-threading
  • Multi-tasking Fundamentals
    •  There are two distinct types of multi-tasking:
      • Process Based
      • Thread Based
  • Process Based
    • A Process is a unit of Isolation on a single machine. Processes are fully isolated from each other;
    • Multiple Processes do have to share access to the processing cores, but do not share virtual memory address space and can run in different security contexts.
    • This is the model that web servers have used in the past to process multiple requests.
  • Thread Based
    • Threads are independently schedulable sets of instructions with a package of nonshared resources.
    • A thread is bounded within a process.
    • A thread cannot migrate from one process to another.
    • All threads within a process share process-wide resources such as heap memory and operating system resources such as file handles and sockets.
    • The queue-based approach is also applicable to multiple threads, as it is in fact a general purpose asynchronous pattern.
    • Due to the heavy sharing of resources, using multiple threads benefits a lot from this approach.
    • Resource sharing also introduces less complexity in coordinating multiple worker threads and handling thread failure.
  • Why Multiple-Theads preferred over Multiple-Processes
    •  Windows processes are relatively heavyweight constructs when compared with threads.
    • This is due to the loading of the Win32 runtime libraries and the associated registry reads (along with a number of cross-process calls to system components for housekeeping).
    • Therefore, by design on Windows, we tend to prefer using multiple threads to create asynchronous processing rather than multiple processes.
  • Thread Scheduling
    • In Windows, the operating system component responsible for mapping thread execution on to cores is called the Thread Scheduler.
    • As we shall see, sometimes threads are waiting for some event to occur before they can perform any work (in .NET this state is known as SleepWaitJoin).
    • Any thread not in the SleepWaitJoin state should be allocated some time on a processing core and, all things being equal, the thread scheduler will round-robin processor time among all of the threads currently running across all of the processes.
    • Each thread is allotted a time slice and, as long as the thread doesn’t enter the SleepWaitJoin state, it will run until the end of its time slice.
    • Things, however, are not often equal.
    • Different processes can run with different priorities (there are six priorities ranging from idle to real time).
    • Within a process a thread also has a priority; there are seven ranging from idle to time critical.
    • The resulting priority a thread runs with is a combination of these two priorities, and this effective priority is critical to thread scheduling.
    • if a higher-priority thread wants to run, then a lower-priority thread is ejected from the processor (preempted) and replaced with the higher-priority thread.
    • Threads of equal priority are, again, scheduled on a round-robin basis, each being allotted a time slice.
    • You may be thinking that lower-priority threads could be starved of processor time. However, in certain conditions, the priority of a thread will be boosted temporarily to try to ensure that it gets a chance to run on the processor. Priority boosting can happen for a number of reasons (e.g., user input). Once a boosted thread has had processor time, its priority gets degraded until it reaches its normal value.
  • Threads and Resources
    •  Although two threads share some resources within a process, they also have resources that are specific to themselves.
    • Thread-Specific Resources
      • The Stack
      • Each thread gets its own stack. This means that local variables and parameters in methods, which are stored on the stack, are never shared between threads. The default stack size is 1MB, so a thread consumes a considerable amount of resource in just its allocated stack.
      • Thread Local Storage
      • All threads of a process share its virtual address space.
      • The local variables of a function are unique to each thread that runs the function. However, the static and global variables are shared by all threads in the process.
      • With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index. 
      • This value is specific to the thread and cannot be accessed by other threads. 
      • TLS slots are limited in number, The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. which at the time of writing is guaranteed to be at least 64 per process but may be as high as 1,088.
      • Registers
      • A thread has its own copy of the register values. 
      • When a thread is scheduled on a processing core, its copy of the register value is restored on to the core’s registers. This allows the thread to continue processing at the point when it was preempted (its instruction pointer is restored) with the register state identical to when it was last running.
      •  

LINQ in C# - Non-Deferred Operator Examples - Aggregating

Count

Count - Type 1 Example 1

         string[] names = {"Arun", "Raja", "Ramkumar", "RaviRajan" };

                    int Count = names.Count(); // 4
        

Count - Type 2 with Condition Example 1

string[] names = {"Arun", "Raja", "Ramkumar", "RaviRajan" };

                        int Count = names.Count(x=> x.Length==4); // 2

LongCount

The LongCount operator returns the number of elements in the input sequence as a long.
string[] names = {"Arun", "Raja", "Ramkumar", "RaviRajan" };

                        long Count = names.LongCount(x=> x.Length==4); // 2

Sum

The Sum operator cannot have conditions
nt[] names = {1, 2, 3 , 4};

                        int sum= names.Sum()// 10

Min/Max

The Min/Max operator cannot have conditions

Min/Max - Type 1 - Example


                         int[] numbers = {1, 2, 3 , 4};
                        string[] names = { "Person A","Person B", "Person C", "Person D" };     

                        string minString = names.Min(); // Person A
                        Console.WriteLine(minString);
                        int minInt = numbers.Min(); // 1
                        Console.WriteLine(minInt);

Min/Max - Type 2 with Property Selector- Example

List<Customer> Customers = new List<Customer> {
                                    new Customer(){ CustomerID=1, Name="XYZ Private Limited", CustomerType="WholeSale" },
                                    new Customer(){ CustomerID=2, Name="ABC Private Limited", CustomerType="WholeSale" },
                                    new Customer(){ CustomerID=2, Name="MS Infotech", CustomerType="Retail" },
                                    new Customer(){ CustomerID=4, Name="Oracle" , CustomerType="WholeSale" },
                                    new Customer(){ CustomerID=5, Name="IBM Hardware Limited", CustomerType="Retail" },
                                 };

                        string MinCustomerName = Customers.Min(x=> x.Name);
                        Console.WriteLine(MinCustomerName);
//Output
ABC Private Limited

Average

The Average operator returns the average of numeric values contained in the elements of the input sequence.

Average - Type 1 - Example 1

Average returns double return type
 
int[] numbers = {1, 2, 3 , 4};
                        double Avg = numbers.Average();
                        Console.WriteLine(Avg);  // 2.5

Average - Type 2 with Property Selector- Example

class Order
    {
        public int OrderID { get; set; }
        public int CustomerID { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal Total { get; set; }     
    }

List<Order> Orders = new List<Order> {
                                    new Order(){ OrderID=1, OrderDate=new DateTime(2020,10,1), CustomerID=1, Total=1025.24M },
                                    new Order(){ OrderID=2, OrderDate=new DateTime(2020,4,1), CustomerID=1, Total=1000.24M },
                                    new Order(){ OrderID=3, OrderDate=new DateTime(2020,4,1), CustomerID=2, Total=1140.24M },
                                    new Order(){ OrderID=4, OrderDate=new DateTime(2020,2,1), CustomerID=2, Total=1160.24M },
                                    new Order(){ OrderID=5, OrderDate=new DateTime(2020,1,1), CustomerID=3, Total=1567.24M },
                                 };

decimal OrderAverage = Orders.Average(x=> x.Total);
                        Console.WriteLine(OrderAverage);

Aggregate

The easiest-to-understand definition of Aggregate is that it performs an operation on each element of the list taking into account the operations that have gone before.

Aggregate - Type 1 Example 1 Summing numbers

int[] numbers = {1, 2, 3 , 4};                   
                        var sum = numbers.Aggregate((a, b) => a + b); //output: 10 (1 + 2 + 3 + 4)
                        Console.WriteLine(sum);
This adds 1 and 2 to make 3. Then adds 3 (result of previous) and 3 (next element in sequence) to make 6. Then adds 6 and 4 to make 10.

Aggregate - Type 1 Example 2 create a csv from an array of strings

var chars = new[] { "a", "b", "c", "d" };
            var csv = chars.Aggregate((a, b) => a + ',' + b);
            Console.WriteLine(csv); // Output a,b,c,d

Aggregate - Type 2 Example 1 Summing numbers with a seed

int[] numbers = {1, 2, 3 , 4};                   
                        var sum = numbers.Aggregate(10, (a, b) => a + b); //output: 20 = (10 + 1 + 2 + 3 + 4)
                        Console.WriteLine(sum);

Aggregate - Type 2 Example 2 with a seed

var chars = new[] { "a", "b", "c", "d" };
            var csv = chars.Aggregate(new StringBuilder(), (a, b) => {
                if (a.Length > 0)
                    a.Append(",");
                a.Append(b);
                return a;
            });
            Console.WriteLine(csv);
//Output
a,b,c,d

LINQ in C# - Non-Deferred Operator Examples- Any/All/Contains - Quntifiers

Any

The Any operator returns true if any one element of an input sequence matches a condition.

Any - Type 1 - without condition - Example

  • Any without conditions, but a source sequence with at least with a single element. will return true
  string[] names = {"Name1", "Name2", "Name3", "Name4" };

            bool found = names.Any();

            Console.WriteLine(found);
//Output
True
  • Any without conditions, with a source sequence with zero element will return false.
string[] names = {};

            bool found = names.Any();

            Console.WriteLine(found);
 //Output
false

Any - Type 2 - with condition - Example

string[] names = {"Ramkumar", "Rajesh", "Manikandan", "Ram" };

            bool ThreeLetterNamefound = names.Any(x=> x.Length==3);
            Console.WriteLine(ThreeLetterNamefound); //True

            bool FourLetterNamefound = names.Any(x => x.Length == 4);
            Console.WriteLine(FourLetterNamefound); //False

All

The All operator returns true if every element in the input sequence matches a condition.
All needs to have at least one condition, it is mandatory 

string[] names = {"Arun", "Raja" };

            bool ThreeLetterNamefound = names.All(x=> x.Length == 4);
            Console.WriteLine(ThreeLetterNamefound); //True
 //Output
True 

Contains

The Contains operator returns true if any element in the input sequence matches the specified value.

Contains - Type 1 - Example 1

string[] names = {"Arun", "Raja", "Ramkumar", "RaviRajan" };

            bool Namefound = names.Contains("Raja");
            Console.WriteLine(Namefound); //True

Contains - Type 2 with Custom Comparer - Example 1

Implementation of IEqualityComparer, just for shown here for show how IEqualityComparer works


class StringComparer : IEqualityComparer<string>
    {
        public bool Equals(string x, string y)
        {
            //throw new NotImplementedException();
            return x.Length == y.Length;
        }

        public int GetHashCode(string obj)
        {
            //throw new NotImplementedException();
            return obj.GetHashCode();
        }
    }

 string[] names = {"Arun", "Raja", "Ramkumar", "RaviRajan" };

            bool Namefound = names.Contains("abcd", new StringComparer());
            Console.WriteLine(Namefound); //True

            bool NamefoundFalse = names.Contains("abc", new StringComparer());
            Console.WriteLine(Namefound); //False becuase there is no element with 3 letters

LINQ in C# - Non-Deferred Operator Examples- First vs Single/SingleDefault - ElementAt/ElementAtOrDefault- Equality

Single

  • Both First() and Single() will return single element from the source sequence.
  • First() requires at least 1 element, that can be any element from the source squence
  • But Single()  has a special requirements for the sequence
    • If Single() call without a lambda expression as input then the sequence should have only one element 
int[] numbers = {5};

            int found = numbers.Single();
            Console.WriteLine(found);
//Output
5
    • If Single() call with a lambda expression as input then the sequence should have only one matching element for the given lambda expression
int[] numbers = {1, 2, 3};

            int found = numbers.Single(x=> x == 2);
            Console.WriteLine(found);
    • if both the cases doesn't met, Exception will be raised 

SingleOrDefault

  • Works same as FirstDefault

Element / ElementAtDefault

  • Looks for the element at a particular index
string[] names = {"Name1", "Name2", "Name3", "Name4" };

            string found = names.ElementAt(2);

            Console.WriteLine(found);
//Output
Name3
string[] names = {"Name1", "Name2", "Name3", "Name4" };

            string found = names.ElementAtOrDefault(5);
            Console.WriteLine(found);

LINQ in C# - Non-Deferred Operator Examples- (First, FirstOrDefault, Last, LastOrDefault) - Equality

First/Last - Type 1 Example 1

  • First will raise error(System.InvalidOperationException: 'Sequence contains no matching element'),  if cannot find element in the first position that is no element in the squence
string[] presidents = { "Adams", "Arthur", "Buchanan", "Bush", "Carter",
                                    "Cleveland", "Clinton", "Coolidge", "Eisenhower",
                                    "Fillmore", "Ford", "Garfield", "Grant", "Harding",
                                    "Harrison", "Hayes", "Hoover", "Jackson", "Jefferson",
                                    "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
                                    "Monroe", "Nixon", "Obama", "Pierce", "Polk", "Reagan",
                                    "Roosevelt", "Taft", "Taylor", "Truman", "Tyler", "Van Buren",
                                    "Washington", "Wilson" };

            Console.WriteLine(presidents.First());
//Output
Adams

First/Last - Type 2 Example 1

 Console.WriteLine(presidents.First(x=> x.StartsWith("H")));

//Output
Harding

FirstOrDefault/LastOrDefault - Example 1

  • Return first element in the sequence if not found return default value of the return type
string foundName = presidents.Take(0).FirstOrDefault();
Console.WriteLine(foundName);


string found = presidents.FirstOrDefault(x => x.Length>20);
            Console.WriteLine(found);

LINQ in C# - Non-Deferred Operator Examples- SequenceEqual - Equality

SequenceEqual

  • The SequenceEqual operator determines whether two input sequences are equal.

Type 1 - Example 1

 List<int> ItemSeq1 = new List<int> { 1, 2, 3 };
 List<int> ItemSeq2 = new List<int> { 1, 2, 3 };

            Console.WriteLine(ItemSeq1.Equals(ItemSeq2));
            Console.WriteLine(ItemSeq1.Equals(ItemSeq1));
//Output
false
true
  • How SequenceEqual it works?
  • SequenceEqual returns true 
    • If the two source sequences are of equal length and their corresponding elements are equal according to the default equality comparer for their type

Type 1 - Example 2

class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}

public static void SequenceEqualEx1()
{
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
Pet pet3 = new Pet { Name = "Turbo", Age = 2 };
Pet pet4 = new Pet { Name = "Peanut", Age = 8 };

// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
List<Pet> pets3 = new List<Pet> { pet3, pet4 };
List<Pet> pets4 = new List<Pet> { pet3, pet4 };

bool Areequal1 = pets1.SequenceEqual(pets2);
bool Areequal2 = pets3.SequenceEqual(pets4);
bool Areequal3 = pets1.SequenceEqual(pets3);
bool Areequal4 = pets1.SequenceEqual(pets3);

Console.WriteLine("The lists {0} equal.", Areequal1 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal2 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal3 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal4 ? "are" : "are not");

}
 
//Output
The lists are equal.
The lists are equal.
The lists are not equal.
The lists are not equal.

Type 2 - Example 1 using IEquatable Interface

  • If you want to compare the actual data of the objects in the sequences instead of just comparing their references, you have to implement the IEquatable Interface generic interface in your class.
class Pet : IEquatable<Pet>
{
public string Name { get; set; }
public int Age { get; set; }

public bool Equals(Pet other)
{
if (other is null)
return false;

return this.Name == other.Name && this.Age == other.Age; // Compare with Values
}
}


public static void SequenceEqualEx1()
{
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
Pet pet3 = new Pet { Name = "Turbo", Age = 2 };
Pet pet4 = new Pet { Name = "Peanut", Age = 8 };

// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
List<Pet> pets3 = new List<Pet> { pet3, pet4 };
List<Pet> pets4 = new List<Pet> { pet3, pet4 };

bool Areequal1 = pets1.SequenceEqual(pets2);
bool Areequal2 = pets3.SequenceEqual(pets4);
bool Areequal3 = pets1.SequenceEqual(pets3);
bool Areequal4 = pets1.SequenceEqual(pets3);

Console.WriteLine("The lists {0} equal.", Areequal1 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal2 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal3 ? "are" : "are not");
Console.WriteLine("The lists {0} equal.", Areequal4 ? "are" : "are not");

}
 
//Output
The lists are equal.
The lists are equal.
The lists are equal.
The lists are equal.

Type 2 - Example 2 using IEqualityComparer Interface

class PetComparer : IEqualityComparer<Pet>
    {
        public bool Equals(Pet x, Pet y)
        {
            if (x is null || y is null)
                return false;

            return x.Name == y.Name && x.Age == y.Age; // Compare with Values
        }

        public int GetHashCode(Pet obj)
        {
            return obj.Name.Length; // Just for returning some integer, there is no logic used here
        }
    }
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }       
    }


            Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
            Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
            Pet pet3 = new Pet { Name = "Turbo", Age = 2 };
            Pet pet4 = new Pet { Name = "Peanut", Age = 8 };

            // Create two lists of pets.
            List<Pet> pets1 = new List<Pet> { pet1, pet2 };
            List<Pet> pets2 = new List<Pet> { pet1, pet2 };
            List<Pet> pets3 = new List<Pet> { pet3, pet4 };
            List<Pet> pets4 = new List<Pet> { pet3, pet4 };

            bool Areequal1 = pets1.SequenceEqual(pets2, new PetComparer());
            bool Areequal2 = pets3.SequenceEqual(pets4, new PetComparer());
            bool Areequal3 = pets1.SequenceEqual(pets3, new PetComparer());
            bool Areequal4 = pets1.SequenceEqual(pets3, new PetComparer());

            Console.WriteLine("The lists {0} equal.", Areequal1 ? "are" : "are not");
            Console.WriteLine("The lists {0} equal.", Areequal2 ? "are" : "are not");
            Console.WriteLine("The lists {0} equal.", Areequal3 ? "are" : "are not");
            Console.WriteLine("The lists {0} equal.", Areequal4 ? "are" : "are not");
//Output
The lists are equal.
The lists are equal.
The lists are equal.
The lists are equal.

Framework Fundamentals - String - Comparing Strings

In comparing two values, the .NET Framework differentiates the concepts of equality comparison and order comparison . Equality compariso...