简体   繁体   中英

C# multithreading combined with async/await

This is yet another question related to multi-threading in C#.

However, when multi-threading combined with async/await seems to be interesting.

I have a method generating threads which invoke methods of objects asynchronously.

However, the context is not shared by objects of different classes.

For example, consider the code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadDataSharing
{
    class Data
    {
        public static ThreadLocal<string> Name = new ThreadLocal<string>();
    }

    class Locker { public static object lobj = new object { };}
    class Program2
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                var pObj = new Program();
                new Thread(new ThreadStart(pObj.MyThreadMethod)).Start();
            }
        }
    }
    class Program
    {

        ///my async method
        ///
        public async Task MyAsyncMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From async method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await MyAsyncMethod2();

            await new AsyncClass().AsyncMethod();
        }

        public async Task MyAsyncMethod2()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From async 2 method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await Task.Run(() =>
            {
                lock (Locker.lobj)
                {
                    Console.WriteLine("From task run method");
                    Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                    Console.WriteLine("id: " + Data.Name.Value);
                }
            });
        }

        public void MyThreadMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From thread method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);

                var id = Guid.NewGuid();
                Data.Name.Value = id.ToString();
                Console.WriteLine("id: " + Data.Name.Value);
            }

            MyAsyncMethod().Wait();
        }
    }


    public class AsyncClass
    {
        public async Task AsyncMethod()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From class async method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            var newId = Guid.NewGuid();
            Data.Name.Value = newId.ToString();

            await AsyncMethod2();
        }

        public async Task AsyncMethod2()
        {
            lock (Locker.lobj)
            {
                Console.WriteLine("From class async 2 method");
                Console.WriteLine("thread: " + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine("id: " + Data.Name.Value);
            }

            await Task.Run(() => { });
        }
    }

}

Running this code produces the following output on my machine

From thread method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From thread method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From thread method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From async method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From async method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From async method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From async 2 method
thread: 3
id: 3a7ef8e3-ebe1-49e1-94bb-798358ac1567
From async 2 method
thread: 4
id: 341d3371-f905-4e1c-aac3-47bda16c8d88
From async 2 method
thread: 5
id: b7e79901-81b7-430f-b158-59f091e43a0c
From task run method
thread: 6
id:
From task run method
thread: 8
id:
From task run method
thread: 7
id:
From class async method
thread: 7
id:
From class async method
thread: 6
id:
From class async method
thread: 8
id:
From class async 2 method
thread: 8
id: f52ed654-0e55-4906-bfc1-65c6b25a7785
From class async 2 method
thread: 7
id: 1e53e03b-a3a0-4296-8622-7716b45d1462
From class async 2 method
thread: 6
id: 1adca81d-b11a-4860-b37d-a017afe877b8

Question is, why is it not sharing the ThreadLocal<T> object with the instance of the second Class ( AsyncClass )?

在具有await / async的控制台应用程序中,没有共享的同步上下文,这可能是不共享同步上下文的原因。

the context is not shared by objects of different classes.

Actually, the behavior you're seeing is that the (thread-local) context is not shared between threads .

I have an async intro blog post that may clear up this behavior. The essential concept is that async methods do not resume on the same thread ; rather, they resume on a captured context (by default). In this case, the thread pool context is used to resume your async methods, which means that those continuations are just scheduled to the thread pool, and may be run by any thread pool thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM