Summary: Tasks, Threads, and Synchronization

Recently I read the book "C#Advanced Programming" again. I want to make a note of the knowledge points in the chapter "Tasks, Threads and Synchronization", so that I can forget that a knowledge point can be used directly in future work. Here is a summary.

Parallel Data and Tasks Parallel

1. Parallel.For

1. Run iteration in parallel with Parallel.For

static void ParallelFor()
{
    ParallelLoopResult result = Parallel.For(0, 10, item =>
    {
        Console.WriteLine("{0},task{1},thread{2}",
            item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10);
    });
    Console.WriteLine("Complete:{0}", result.IsCompleted);
}

2. Stop the For cycle early by using ParallelLoopState's Break() method

static void ParallelForBreak()
{
    ParallelLoopResult result = Parallel.For(0, 10, (item, pls) =>
    {
        Console.WriteLine("{0},task{1},thread{2}",
            item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10);
        if (item > 5) pls.Break();
    });
    Console.WriteLine("Complete:{0}", result.IsCompleted);
    Console.WriteLine("Ignore:{0}", result.LowestBreakIteration);
}

3. Initialize each thread

static void ParallelForInit()
{
    ParallelLoopResult result = Parallel.For<string>(0, 20,
        () =>
        //Func<TLocal>Call once for each thread used to perform iteration
        {
            Console.WriteLine("Initialize, Task:{0},Threads:{1}",
            Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            return string.Format("Threads:{0}", Thread.CurrentThread.ManagedThreadId);
        },
        (item, pls, str1) =>
        //Func<long, ParallelLoopState, TLocal, TLocal> Delegates defined for the loop body
        //The first parameter is the loop iteration, the second parameter ParallelLoopState Allow stop loop
        //The third parameter receives the value returned by the initialization task, and the type is generic For Parameter Defined
        {
            Console.WriteLine("In execution, number:{0},str1: {1},Tasks:{2},Threads:{3}",
                item, str1, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(10);
            return string.Format("Number:{0}", item);
        },
        (str1) =>
        //Action<TLocal> This method is called only once per thread, this is a thread exit method
        {
            Console.WriteLine("Complete:{0}", str1);
        });
}

4. Cancel Tasks

/// <summary>
/// Cancel Task
/// </summary>
static void ParallelCancel()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    //Register a delegation when a task is cancelled
    cts.Token.Register(() =>
    {
        Console.WriteLine("Task cancelled");
    });
    try
    {
        ParallelLoopResult result = Parallel.For(0, 10,
            new ParallelOptions()
            {
                CancellationToken = cts.Token
            },
            item =>
            {
                Console.WriteLine("Cycle:{0}", item);
                Thread.Sleep(1000);
                if (item == 5) cts.Cancel();
            });
    }
    catch (OperationCanceledException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

2. Parallel.ForEach

1. Traverse asynchronously with Parallel.ForEach

static void ParallelForeach()
{
    string[] data = { "Zhang San", "Li Si", "King Five", "Zhao Six", "Qian Qi" };
    ParallelLoopResult result = Parallel.ForEach(data, item =>
    {
        Console.WriteLine("Value:{0},Tasks:{1},Threads:{2}",
            item, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
    });
}

2. Break() method of ParallelLoopState to interrupt ForEach traversal

static void ParallelForeachBreak()
{
    string[] data = { "Zhang San", "Li Si", "King Five", "Zhao Six", "Qian Qi" };
    ParallelLoopResult result = Parallel.ForEach(data, (item, pls, index) =>
    {
        Console.WriteLine("Value:{0},Indexes:{1},Tasks:{2},Threads:{3}",
            item, index, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        if (item == "King Five") pls.Break();
    });
}

3. Parallel.Invoke

1. Call multiple methods through the Parallel.Invoke() method. If multiple tasks should run in parallel, you can use the Parallel.Invoke method, which provides a task parallelism mode

static void ParallelInvoke()
{
    Parallel.Invoke(Zhangsan, Lisi);
}
static void Zhangsan()
{
    Console.WriteLine("Zhang San");
}
static void Lisi()
{
    Console.WriteLine("Li Si");
}

Task Task Task

1. Create a method for task execution.

static object taskMethodLock = new object();
static void TaskMethod(object title)
{
    lock (taskMethodLock)
    {
        Console.WriteLine(title);
        Console.WriteLine("Tasks:{0},Threads:{1}",
            Task.CurrentId == null ? -1 : Task.CurrentId,
            Thread.CurrentThread.ManagedThreadId);
        Console.WriteLine("Thread pool:{0}", Thread.CurrentThread.IsThreadPoolThread);
        Console.WriteLine("Background threads:{0}", Thread.CurrentThread.IsBackground);
        Console.WriteLine();
    }
}

2. Creating tasks in different ways

/// <summary>
/// Create tasks in different ways
/// </summary>
static void CreateTask()
{
    //Mode 1: Use instantiated TaskFactory class
    TaskFactory tf = new TaskFactory();
    Task task = tf.StartNew(TaskMethod, "Use TaskFactory Class Start Task");
    //Mode 2: Use Task Static Properties of Classes Factory
    Task.Factory.StartNew(TaskMethod, "Use Task Static Properties of Classes Factory Start Task");
    //Mode 3: Use Task Constructor of class
    Task task1 = new Task(TaskMethod, "Use Task Class Constructor Start Task");
    task1.Start();
}

3. Creating synchronization tasks

/// <summary>
/// Synchronize Tasks
/// </summary>
static void SyncTask()
{
    TaskMethod("Main Thread");
    Task task = new Task(TaskMethod, "Synchronize Tasks");
    task.RunSynchronously();
}

4. Create long-running tasks

/// <summary>
/// Create long-running tasks
/// </summary>
static void LongRunTask()
{
    //Create a new thread instead of using threads in the thread pool
    Task task = new Task(TaskMethod, "Long running tasks", TaskCreationOptions.LongRunning);
    task.Start();
}

V. Outcomes of Tasks

/// <summary>
/// Result of the task
/// </summary>
static void TaskResult()
{
    Task<string> task = new Task<string>((name) =>
    {
        Console.WriteLine(name);
        return string.Format("My name is:{0}", name);
    }, "Zhang San");
    task.Start();
    Console.WriteLine(task.Result);
    task.Wait();
}

6. Continuous tasks

/// <summary>
/// Continuous Tasks
/// </summary>
static void ContinueTask()
{
    Task task1 = new Task(() =>
    {
        Console.WriteLine("Task Start:{0}", Task.CurrentId);
        Thread.Sleep(3000);
    });
    //task1 Execute immediately after completion task2
    Task task2 = task1.ContinueWith((task) =>
    {
        Console.WriteLine("Complete tasks:", task.Id);
        Console.WriteLine("Current Task:", Task.CurrentId);
        Console.WriteLine("Do some cleanup");
        Thread.Sleep(3000);
    });
    task1.Start();
}

7. Task Hierarchy

/// <summary>
/// Parent-Child Tasks
/// </summary>
static void ParentAndChildTask()
{
    Task parent = new Task(ParentTask);
    parent.Start();
    Thread.Sleep(2000);
    Console.WriteLine(parent.Status);
    Thread.Sleep(4000);
    Console.WriteLine(parent.Status);
}
static void ParentTask()
{
    Console.WriteLine("Task number:", Task.CurrentId);
    Task child = new Task(ChildTask);
    child.Start();
    Thread.Sleep(1000);
    Console.WriteLine("Start Subtask");
}
static void ChildTask()
{
    Console.WriteLine("Subtasks");
    Thread.Sleep(5000);
    Console.WriteLine("Subtask Completion");
}

8. Cancel Tasks

//Cancel Task
static void CancelTask()
{
    CancellationTokenSource cts = new CancellationTokenSource();
    cts.Token.Register(() => { Console.WriteLine("Execute after the task is cancelled"); });

    Task task = new Task(() =>
    {
        Console.WriteLine("Start Task");
        for (int i = 0; i < 100; i++)
        {
            CancellationToken token = cts.Token;
            if (token.IsCancellationRequested)
            {
                Console.WriteLine("Task cancelled");
                token.ThrowIfCancellationRequested();
            }
            Thread.Sleep(100);
            Console.WriteLine("Cycle number:{0}", i);
            if (i == 5) cts.Cancel();
        }
    }, cts.Token);
    task.Start();
    try
    {
        task.Wait();
    }
    catch (AggregateException ex)
    {
        Console.WriteLine("Exception:{0},{1}", ex.GetType().Name, ex.Message);
        foreach (var innerException in ex.InnerExceptions)
        {
            Console.WriteLine("Internal exception:{0},{1}",
                ex.InnerException.GetType().Name, ex.InnerException.Message);
        }
    }
}

ThreadPool Thread Pool

static void ThreadPoolDemo()
{
    int workerThreads;
    int completionPortThreads;
    ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
    Console.WriteLine("Work Threads:{0},IO Threads:{1}", workerThreads, completionPortThreads);
    for (int i = 0; i < 5; i++)
    {
        ThreadPool.QueueUserWorkItem(TaskMethod);
    }
}
static void TaskMethod(object state)
{
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine("Cycle:{0},Threads:{1}", i, Thread.CurrentThread.ManagedThreadId);
    }
}

Thread class

1. Create a thread

/// <summary>
/// Create a thread
/// </summary>
static void CreateThread()
{
    Thread thread = new Thread(() =>
    {
        Console.WriteLine("This is a thread,{0}", Thread.CurrentThread.ManagedThreadId);
    });
    thread.Start();
    Console.WriteLine("This is a main thread,{0}", Thread.CurrentThread.ManagedThreadId);
}

2. Passing data to threads

1. Mode 1, using the Thread constructor with the ParameterizedThreadStart delegate parameter

/// <summary>
/// Pass data to thread (mode 1)
/// </summary>
static void ThreadWithData1()
{
    var data = new { Message = "This is a message" };
    Thread thread = new Thread((state) =>
    {
        var obj = (dynamic)state;
        Console.WriteLine(obj.Message);
    });
    thread.Start(data);
}

2. Mode 2, create a custom class that defines the thread's method as the instance method so that after initializing the instance's data, the thread can be started.

class MyThread
{
    private string message = string.Empty;
    public MyThread(string message)
    {
        this.message = message;
    }

    public void ThreadMain()
    {
        Console.WriteLine(message);
    }
}
/// <summary>
/// Pass data to thread (mode 2)
/// </summary>
static void ThreadWithData2()
{
    MyThread myThread = new MyThread("This is a message");
    Thread thread = new Thread(myThread.ThreadMain);
    thread.Start();
}

3. Background Threads

/// <summary>
/// Background Threads
/// </summary>
static void BackgroundThread()
{
    Thread thread = new Thread(() =>
    {
        Console.WriteLine("Thread starts:{0}",Thread.CurrentThread.Name);
        Thread.Sleep(3000);
        Console.WriteLine("Thread complete startup:{0}", Thread.CurrentThread.Name);
    });
    thread.Name = "MyThread";
    thread.IsBackground = true;
    thread.Start();
}

Keywords: C# Programming

Added by jschofield on Sat, 15 Jun 2019 20:58:24 +0300