7

私は、設計が不十分なソリューションに悩まされてきました。スレッドセーフではありません!

ソリューションにはいくつかの共有クラスとメンバーがあり、開発中はすべてクールでした...
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 コールです。

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 にあります。

どんな助けでも大歓迎です。コードをスレッドセーフにする作業を続けますが、これが「単純な」答えになると思います。

他に思い当たる人がいたら、どうぞ。

ありがとう、
キース

完全を期すためだけに。

「Transport Advanced Options」ダイアログで送信アダプタを「Ordered Delivery」としてマークすると、発生していたマルチスレッドの問題を回避できることがわかりました。

これは私の問題に対する別の可能な答えだと思いますが、必ずしも質問に対するものではありません。

4

6 に答える 6

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);       
    }
}
于 2008-11-21T04:15:03.860 に答える
3

スレッドセーフの観点から、正確にはどの部分が苦痛ですか? 静的な状態もシングルトンも見えません - そして適切な「新しい」オブジェクトがあるようです...私は盲目ですか?

では、どのような症状が見られるのでしょうか...

AppDomain の回答は (比較的) 遅くなります。ミドルウェアに支えられたシステムの一部として、これは問題ないかもしれません (つまり、「相対的に」は同じ球場にあります)。

どこに静的な状態がある場合、時々機能する別のオプションは [ThreadStatic] です。これは、ランタイムが「この静的フィールドはスレッドごとに一意である」と解釈します。ただし、初期化には注意が必要です。スレッド A の静的コンストラクターはフィールドを割り当てる可能性がありますが、スレッド B は null/0/etc を参照します。

于 2008-11-21T05:28:11.140 に答える
0

完全を期すためだけに。

「Transport Advanced Options」ダイアログで送信アダプタを「Ordered Delivery」としてマークすると、発生していたマルチスレッドの問題を回避できることがわかりました。

これは私の問題に対する別の可能な答えだと思いますが、必ずしも質問に対するものではありません。

于 2008-11-22T00:31:59.367 に答える
0

互いに競合する static を共有している場合は、それらに [ThreadStatic] 属性を追加してみてください。これにより、それらは各スレッドに対してローカルになります。それは短期的にあなたの問題を解決するかもしれません. 正しい解決策は、単にスレッドセーフになるように再構築することです。

于 2008-11-21T17:16:18.433 に答える
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();
        }

    }

}
于 2008-11-20T23:41:44.367 に答える
0

呼び出しごとに appdomain を作成して解体する - この 1 つのパフォーマンスについて心配していないと思いますか?

理想的には、呼び出されたコードをスレッドセーフに変更する必要があります。

于 2008-11-28T11:52:21.473 に答える