如何在属于不同类的不同线程之间共享数据?

时间:2017-10-13 10:52:22

标签: c# multithreading threadcontext

我最近正在阅读关于async / await的内容,我想知道如何在属于不同类的不同线程之间共享数据?假设我们在某些Web应用程序中有HttpContext。此上下文包含有关userIdsessionId等的信息。我们的Web应用程序提供了一些在另一台计算机上执行的控制台应用程序使用的数据。如果此控制台应用程序中发生错误,我会将其写入日志文件。 userIdsessionId也应该写入此日志文件。但在此控制台应用程序中创建的每个线程都有自己的上下文所以,我正在寻找一种方法来将userIdsessionId设置为线程上下文。我不想使用一些静态类或volatile字段。我在下面给出了一个简单的控制台应用程序示例。

    public sealed class MainService
    {
        /// <summary>
        /// The main method which is called.
        /// </summary>
        public void Execute()
        {
            try
            {
                searchService.ExecuteSearchAsync().Wait();
            }
            catch (Exception e)
            {
                // gets additional info (userId, sessionId) from the thread context
                StaticLoggerClass.LogError(e);
            }
        }
    }

    public sealed class SearchService
    {
        private IRepository  repository = new Repository();

        public async Task ExecuteSearchAsync()
        {
            try
            {
                var result = await this.GetResultsAsync();
            }
            catch (Exception e)
            {
                // gets additional info (userId, sessionId) from the thread context
                StaticLoggerClass.LogError(e);
            }
        }

        private async Task<ResultModel> GetResultsAsync()
        {
            var result = this.repository.GetAsync();
        }
    }

    public sealed class Repository
    {
        private IClient client;

        public async Task<Entity> GetAsync()
        {
            return await client.GetResultAsync();
        }
    }

1 个答案:

答案 0 :(得分:1)

几乎没有必要将数据设置为线程上下文&#39;,所以把它放在脑后。

你正在考虑线程安全是很好的 - 大多数问题都是因为人们没有。但是,在这种情况下,没有必要有两个原因:

  1. 根据你的说法,userId和sessionId在此期间不会改变 这个例子的生命。许多请求可能同时运行,但是 每个堆栈都有自己的userid / sessionid

  2. 我投注的userid / sessionid是不可变类型 - 即不能 改变。如果它们是字符串,整数或任何值,则属于这种情况 类型。

  3. 因此,考虑到这一点,你可以这样做:

    public sealed class MainService
    {
        /// <summary>
        /// The main method which is called.
        /// </summary>
        public void Execute()
        {
            try
            {
                // somehow get the userid/sessionid, you don't say where these are from
                var userId = "?";
                var sessionId = "?"
    
                searchService.ExecuteSearchAsync(userId, sessionId).Wait();
            }
            catch (Exception e)
            {
                // gets additional info (userId, sessionId) from the thread context
                StaticLoggerClass.LogError(e);
            }
        }
    }
    
    public sealed class SearchService
    {
        private IRepository  repository = new Repository();
    
        public async Task ExecuteSearchAsync(string userId, string sessionId)
        {
            try
            {
                var result = await this.GetResultsAsync();
            }
            catch (Exception e)
            {
                // gets additional info (userId, sessionId) from the thread context
                StaticLoggerClass.LogError($"userId={userId}; sessionId={sessionId}; error={e}");
            }
        }
    
        // ........ 
        private async Task<ResultModel> GetResultsAsync()
        {
            var result = this.repository.GetAsync();
        }
    }