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

Posted

技术标签:

【中文标题】如何在属于不同类的不同线程之间共享数据?【英文标题】:How to share data between different threads which belong to different classes? 【发布时间】:2018-03-25 11:45:04 【问题描述】:

我最近正在阅读有关 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();
        
    

【问题讨论】:

线程不属于类。您的代码无论如何都没有使用线程,它使用异步方法。不需要跨线程同步 - await 确保执行将在正确的上下文中继续。当然,除非你用 searchService.ExecuteSearchAsync().Wait(); 阻止它,这意味着没有 await 能够返回 不太确定你要做什么,但听起来你可以通过传递 userId 和 sessionId 作为方法参数来做到这一点 您的问题是什么?你想做什么?你遇到实际问题了吗?这段代码中唯一的问题是public void Execute() 和对Wait() 的调用。该方法应该是异步的 至于日志记录,您使用的是哪个记录器?不同的记录器使用不同的技术来传递环境属性,而不依赖于线程上下文,准确地说,因为这会随着任务而变化。如果您编写自己的记录器并遇到问题,请发布记录器的代码 @PanagiotisKanavos 我有一个 static 记录器类,它执行写入日志文件。它用于Web应用程序和控制台应用程序。它从线程上下文中获取数据。这是 Web 应用程序中的 HttpContext。但我的吊顶申请中没有userIdsessionId。我认为我应该将其设置为控制台应用程序的上下文。 【参考方案1】:

几乎从来没有必要将数据“设置到线程上下文”,所以别想了。

考虑线程安全是件好事——大多数问题都是因为人们没有考虑。但是,在这种情况下不需要有两个原因:

    从你所说的,userId 和 sessionId 在 这个例子的生活。许多请求可能同时运行,但 每个堆栈都有自己的用户 ID/会话 ID

    我打赌 userid/sessionid 是不可变类型 - 即不能 改变了。如果它们是字符串、整数或任何值,就会出现这种情况 输入。

因此,考虑到这一点,您可以这样做:

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();
    

【讨论】:

以上是关于如何在属于不同类的不同线程之间共享数据?的主要内容,如果未能解决你的问题,请参考以下文章

在线程之间共享资源,在不同的Java版本中使用不同的行为

Java多线程与并发库7.多个线程之间共享数据的方式探讨

如何在 GUI 线程和工作线程之间共享数据?

使用 sqlite3 包在 python 中的不同线程之间共享一个:memory: 数据库

java面试之多线程

线程的共享性互斥性原子性可见性有序性