代码之家  ›  专栏  ›  技术社区  ›  Keith Sirmons

如何使用AppDomain限制静态类的作用域以实现线程安全使用?

  •  7
  • Keith Sirmons  · 技术社区  · 16 年前

    我一直被一个设计拙劣的解决方案所困扰。它不是线程安全的!

    我在解决方案中有几个共享类和成员,在开发过程中一切都很酷。。。
    他击沉了我的战舰。

    我们正在使用自定义BizTalk适配器调用我的程序集。适配器正在调用我的代码并并行运行,因此我假设它使用的是同一AppDomain下的多个线程。

    我想做的是让我的代码在它自己的AppDomain下运行,这样我的共享问题就不会相互干扰。

    我想在Process()方法中创建一个新的AppDomain,这样每次BizTalk旋转另一个线程时,它都会有自己版本的静态类和方法。

    BizTalkAdapter代码:

      // this is inside the BizTalkAdapter and it is calling the Loader class //
      private void SendMessage(IBaseMessage message, TransactionalTransmitProperties properties)
        {
    
            Stream strm = message.BodyPart.GetOriginalDataStream();
            string connectionString = properties.ConnectionString;
            string msgFileName = message.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties") as string;
    
    
            Loader loader = new Loader(strm, msgFileName, connectionString);
            loader.Process();
    
            EventLog.WriteEntry("Loader", "Successfully processed: " + msgFileName);
    
        }
    

    public class Loader
    {
    
        private string connectionString;
        private string fileName;
        private Stream stream;
        private DataFile dataFile;
    
        public Loader(Stream stream, string fileName, string connectionString)
        {
            this.connectionString = connectionString;
            this.fileName = fileName;
            this.stream = stream;
        }  
    
        public void Process()
        {
    
            //*****  Create AppDomain HERE *****
            // run following code entirely under that domain
            dataFile = new DataFile(aredStream, fileName, connectionString);
            dataFile.ParseFile();
            dataFile.Save();
            // get rid of the AppDomain here...
    
        }
    
    }
    

    仅供参考:加载程序类与数据文件类位于单独的DLL中。

    如果有人有其他想法,请加入。


    基思

    只是为了完整。

    在“传输高级选项”对话框中,我能够避免

    我必须回答这个问题。

    6 回复  |  直到 12 年前
        1
  •  3
  •   Marc Gravell    16 年前

    确切地说,哪一位是线程安全方面的难点?我看不到任何静态或单态-而且似乎有合适的“新”对象。。。我是瞎了吗?

    那么,你看到的症状是什么。。。

    如果你 在某个地方有一些静态状态,另一个有时有效的选项是[ThreadStatic]——运行时将其解释为“每个线程的这个静态字段是唯一的”。不过,在初始化时需要小心——线程A上的静态构造函数可能会分配一个字段,但是线程B会看到null/0/etc。

        2
  •  3
  •   erlando    16 年前

    public class Loader
    {
    
        private string connectionString;
        private string fileName;
        private Stream stream;
        private DataFile dataFile;
    
        public Loader(Stream stream, string fileName, string connectionString)
        {
            this.connectionString = connectionString;
            this.fileName = fileName;
            this.stream = stream;
        }  
    
        public void Process()
        {
            //*****  Create AppDomain HERE *****
            string threadID = Thread.CurrentThread.ManagedThreadId.ToString();
            AppDomain appDomain = AppDomain.CreateDomain(threadID);
    
            DataFile dataFile = 
                (DataFile) appDomain.CreateInstanceAndUnwrap(
                            "<DataFile AssemblyName>", 
                            "DataFile", 
                            true, 
                            BindingFlags.Default,
                            null,
                            new object[] 
                            { 
                                aredstream, 
                                filename, 
                                connectionString 
                            },
                            null,
                            null,
                            null);
            dataFile.ParseFile();
            dataFile.Save();
    
            appDomain.Unload(threadID);       
        }
    }
    
        3
  •  0
  •   tvanfosson    16 年前

    为什么不在要按顺序执行的代码周围加上一个锁呢? 这将是一个瓶颈,但它应该在多线程环境中工作。

    public class Loader
    {
        private static object SyncRoot = new object();
        private string connectionString;
        private string fileName;
        private Stream stream;
        private DataFile dataFile;
    
        public Loader(Stream stream, string fileName, string connectionString)
        {
            this.connectionString = connectionString;
            this.fileName = fileName;
            this.stream = stream;
        }  
    
        public void Process()
        {
    
            lock(SyncRoot) {
                dataFile = new DataFile(aredStream, fileName, connectionString);
                dataFile.ParseFile();
               dataFile.Save();
            }
    
        }
    
    }
    
        4
  •  0
  •   dviljoen    16 年前

    如果共享的静态相互冲突,则可能需要尝试向其添加[ThreadStatic]属性。这将使它们对每个线程都是本地的。这可能会在短期内解决你的问题。一个正确的解决方案是简单地重新构建您的东西,使之成为线程安全的。

        5
  •  0
  •   Keith Sirmons    16 年前

    只是为了完整。

    我想这是我问题的另一个可能答案,但不一定是这个问题的答案。

        6
  •  0
  •   Ben    16 年前

    理想情况下,您应该将调用的代码更改为线程安全的。