LaboratoryTasks

by Paweł Paduch published 2023/10/27 08:29:00 GMT+2, last modified 2023-11-03T09:19:36+02:00
The first lab with Tasks in C#
  1. First Tasks [0,5 pkt.]
    • Create a solution with the FirstTasks project
    • Rewrite or Copy paste the following code:
      using System;
      using System.Collections.Generic;
      using System.Threading;
      using System.Threading.Tasks;
      
      
      namespace FirstTasks
      {
          class Program
          {
              private const int iterNo = 10;
              static void Main(string[] args)
              {
                  Task t1 = new Task(() =>
                  {
                      Random rand = new Random(Task.CurrentId.Value);//init random generator by currentId as a seed
                      Console.WriteLine($"Thread id {Thread.CurrentThread.ManagedThreadId}");
                      Thread.Sleep(rand.Next(0, 100));
                      for (int i = 0; i < iterNo; i++)
                      {
                          Console.Write($"#{i}# ");
                          Thread.Sleep(rand.Next(500));
                      }
                      Console.WriteLine($"\nTask {Task.CurrentId.Value} finished");
                  });
                  t1.Start();
      
                  Console.WriteLine($"Thread id {Thread.CurrentThread.ManagedThreadId}");
                  Random rand = new Random();
                  Thread.Sleep(rand.Next(0, 100));
                  for (int i = 0; i < iterNo; i++)
                  {
                      Console.Write($"{{{i}}} ");
                      Thread.Sleep(rand.Next(500));
                  }
                  Console.WriteLine("\nMain task finished");
                  }
          }
      }
      
    • Task 1 and Main Task print numbers to the screen at random intervals. At the end, each task prints a message about completed work. Unfortunately, the message from Task 1 is not always visible. Find a solution to this problem.

  2. The task created from Action [0,5 pkt.]
    • Add a static void task2() function to the above program that performs the same job as task t1, with the difference that the iteration number will be framed in square brackets. For example [0],[1],[2]...etc..
    • Task t1 was created using lambda notation (anonymously). Create task t2 that implements the void task2()action.
    • Start t2 immediately after creation.
    • Wait for t2 just after t1

  3. Passing a parameter [0,5 pkt.]
    • Based on the task2 action, create a static void task3(object o) action.
    • Inside the task3 action, cast object o to an int variable and use it instead of iterNo (the number of iterations in the loop)
    • The task3 action is supposed to display the number of iterations in round brackets, i.e. (0), (1), (2),... etc.
    • Create task t3 using the task3 action passing the number of iterations through the parameter.
    • Start t3 right after t2
    • Wait for t3 right after t2

  4. Passing a tuple [0,5 pkt.]
    • Add the following action to the program
       static void task4(object arg)
              {
                  (int id, string name) tupleArg = ((int id, string name))arg; //cast tuple values
                  string taskName = tupleArg.name;
                  int taskId = tupleArg.id;
                  Console.WriteLine($"I'm {taskName} and have ID: {taskId}");
              }
      
    • Create and start a task as follows
      (int id, string name) idName = (4, "Task4"); //tupple
      Task t4 = new Task(task4,idName);
      t4.Start();
      
    • Task 4 uses a tuple (a variable with multiple values). This is a quick way to pass a few parameters without having to define a class and create an object of it.
    • You can also pass the tuple directly to the task:
      Task t4b = new Task(task4,(4, "Task4b"));
      t4b.Start();
      
    • Add wait for t4 right after waiting for t3

  5. Passing an object of a defined class [0,5 pkt.]
    • Create the MyParam class
       public class MyParam
          {
              public string Name { get; set; }
              public int Id { get; set; }
          }
      
    • Create a task5 action that does the same thing as task4 but retrieves data from the passed object (remember to cast to the MyParam class.)
    • Create a myParam object of the MyParam class and initialize the Name and Id fields
    • Create task t5 that performs the task5 action, pass the myParam object
    • Start task t5
    • Add waiting for t5 after waiting for t4

  6. Creating a list of tasks [0,5 pkt.]
    • Declare and set the variable int taskNo = 5; This will be the number of tasks to run.
    • Create list List<Task> t5list = new List<Task>(); 
    • In the loop, create and add taskNo tasks that perform the task5 action. Each task should have an id consistent with the loop iteration number and a name in the form "Task" + i.ToString() 
    • Created tasks start immediately after being added to the list (in iteration of the loop)
    • You can use Task.Factory.StartNew to return a created and started task.
    • Add waiting for all tasks (foreach loop) after waiting for t5.

  7. The Snow project [0,5 pkt.]
    • Add a new Snow project. copy the Star() method code below.
      static void Star(object o)
              {
                  int height = 26;
                  int width = 79;
                  int delay = 200;
                  int orgx;
                  int orgy;
                  ConsoleColor orgcolor;
                  int prevx;
                  int currentx;
                  int prevy = 0;
                  int currenty=0;
                  int iterations = 5; //how many times sars wrap the screen verticaly
                  ConsoleColor? color = null; //if nul then random
                  Random rand = new Random((int)DateTime.Now.Ticks);
                
      // Console.WriteLine($"Task started on thread Id {Thread.CurrentThread.ManagedThreadId}"); currentx = prevx = rand.Next(width - 1); Console.CursorVisible = false; //we don't need blinking cursor for (int y = 0; y < height*iterations; y++) { currenty = y % height; //just from interation currentx = prevx + rand.Next(-1,1); if (currentx < 0) currentx = width; if (currentx > width) currentx = 0; lock (Console.Out) { //remember orginal position and color orgx = Console.CursorLeft; orgy = Console.CursorTop; orgcolor = Console.ForegroundColor; //erease elier star Console.SetCursorPosition(prevx, prevy); Console.Write(' '); //set color and new position if (color == null) Console.ForegroundColor = (ConsoleColor)rand.Next(15); else Console.ForegroundColor = color.Value; Console.SetCursorPosition(currentx, currenty); //put the star Console.Write('*'); //restore position and color Console.SetCursorPosition(orgx, orgy); Console.ForegroundColor = orgcolor; } prevx = currentx; prevy = currenty; Thread.Sleep(delay); } }
      This is an Action that displays a falling colored star. When you reach the edge of the console, an asterisk appears on the other side.
    • Create a list of 50 started tasks with the Star action. The object being passed may be null for now.
    • Wait for all tasks using the Task.WaitAll method

  8. More snow. [0,5 pkt]  
    • If the snowflakes don't all appear at once, uncomment the line  Console.WriteLine($"Task started on thread Id {Thread.CurrentThread.ManagedThreadId}");  and see how many tasks are running at the same time.
    • Change the number of threads in the pool. Before starting, add the line ThreadPool.SetMinThreads(64, 64); 
    • If snowflakes appear in avalanches. Add a random delay from 0 to 100ms before each task creation.

  9. Providing information to Star Action [0,5 pkt.]
    • Create a StarParameter class containing variables such as:
      • Random rand
      • int iterations
      • ConsoleColor? color
    • Before creating a task, create an object of the StarParameter class with a given number of iterations, a random color and a reference to the Random class object.
    • Pass objects to tasks then cast and read data from them.

  10. Additional activities [0,5 pkt.]
    • Secure the random to be threadsafe. (Rand.Shared was introduced in .net 6, it does not require creating an instance and is thread safe by default)
    • The Star action should read the current console size and adjust the calculations so that snow falls on the entire screen, even when the window is enlarged.