如何使用AppDomain限制静态类的范围以便线程安全使用?

时间:2008-11-20 23:35:00

标签: c# thread-safety biztalk appdomain

我被一个架构不佳的解决方案所困扰。它不是线程安全的!

我在解决方案中有几个共享的类和成员,在开发期间一切都很酷......
BizTalk已经沉没了我的战舰。

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

我想做的是让我的代码在自己的AppDomain下运行,这样我所拥有的共享问题就不会相互混淆。

我有一个非常简单的类,BizTalk适配器正在实例化然后运行Process()方法。

我想在我的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);

    }

这是BizTalk Calls类:

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...

    }

}

仅供参考:Loader类位于dataFile类的单独DLL中。

任何帮助将不胜感激。我将继续努力使代码线程安全,但我觉得这可能是“简单”的答案。

如果有任何其他想法,请投入。

谢谢你,
基思

  

只是为了完整。

     

我确实发现如果我将发送适配器标记为“Ordered Delivery”   “传输高级选项”对话框我能够避免   我遇到的多线程问题。

     

我认为这是我问题的另一个可能的答案,但不是   必然要问题。

6 个答案:

答案 0 :(得分:3)

使用应用域您可以执行以下操作:

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

答案 1 :(得分:3)

确切地说,哪一点在线程安全方面是一种痛苦?我看不到任何静态或单身 - 而且似乎有适当的“新”物体......我是不是在盲目?

那么你看到的症状是什么......

AppDomain答案将(相对)缓慢。作为中间件支持系统的一部分,这可能没问题(即“相对”在同一个球场中。)

如果某处有某种静态,另一种有时可行的选项是[ThreadStatic] - 运行时将其解释为“此静态字段对于每个线程是唯一的”。但是你需要小心初始化 - 线程A上的静态构造函数可能会分配一个字段,但是线程B会看到一个null / 0 / etc。

答案 2 :(得分:0)

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

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

    }

}

答案 3 :(得分:0)

如果您有共享相互冲突的静态,那么您可能想尝试将[ThreadStatic]属性添加到它们中。这将使它们成为每个线程的本地。这可能会在短期内解决您的问题。一个正确的解决方案是简单地将你的东西重新架构为线程安全的。

答案 4 :(得分:0)

只是为了完整。

我确实发现如果我在“传输高级选项”对话框中将发送适配器标记为“有序传递”,我就能避免出现我遇到的多线程问题。

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

答案 5 :(得分:0)

为每次通话创建并拆除appdomain - 我认为你不担心这个系统的性能吗?

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