0

並列スレッド タイマーを持つプログラムがあります。基本的に、これらのタイマーは 10 秒ごとにメソッドを実行するように設定されています。そのメソッドでは、スレッドはリストのロックを取得して、その作業を行うためのコピーを作成します。

private object access = new object();
PeriodTask(){
    lock(access){
        copy = list.Where(e => e.valid).toList();
    }
    foreach (var element in copy)
        do some not so quick work.
}

また、ロックを要求する要素に関する情報を取得する方法もあります。そして、コピーを取得します

informationMethod(){
    lock(access){
        return list.Select(element => new serializableElement(element)).toList()

    }
}

ロックが必要な理由は、このリストをロックするアイテムを追加および削除するメソッドがあるためです。しかし、私はまだ彼らに電話さえしていません。

私が抱えている問題は、情報取得メソッドがこのクラスのインスタンス間で長時間ブロックまたはスリープすることです。これらは約 10 個ある可能性があり、一度に 2 つまたは 3 つにアクセスできるように見えますが、すべてを取得するには 1 分半から 2 分かかる場合があります。タイマーで実行される最初のメソッドは、必要なときに問題なくアクセスでき、すぐにロックを解放しますが、他のメソッドは実行のメイン スレッドであるにもかかわらず、実行に苦労します。

これらのクラスのマネージャーをインスタンス化するいくつかのテストがあります。

//sets up updaters test
var manager = new manager(config);
Assert.IsNotNull(manager);
Assert.IsFalse(manager.UpdatersRunning);
Assert.AreNotEqual(0, manager.Updaters.Count());//calls the informationMethod on each updater
manager.Dispose();
//This test doesn't even run the period task


//Waits to start updaters test
var manager = new StatusObjectManager(config);
Assert.IsNotNull(manager);
Assert.AreNotEqual(0, manager.Updaters.Count());
Assert.IsFalse(manager.UpdatersRunning);
Assert.AreEqual(0, manager.Updaters.Count(u => u.Running));
manager.StartUpdaters();
Assert.IsTrue(manager.UpdatersRunning);
Assert.AreNotEqual(0, manager.Updaters.Count(u => u.Running));
manager.Dispose();
//This test runs the period tasks and checks to make sure their running. Or at least 1.
//THis test takes a long time for the first informationMethod bout but not the other 2.

The code in the manager looks like this
return updaters.select(u => new serialUpdater(su));

このリストは変更されていないため、この時点ではロックは必要ありません。

何が起こっているのか誰にもわかりません。スレッドがロックでブロックされているのか、異常な時間だけスリープしているのかを判断する方法がわかりません。

4

1 に答える 1

0

ここでの最初のステップは、ロギングを追加することです。Trace.WriteLineロックの前と内側で単純にThread.CurrentThread.Name、作成時、読み取り時に を取得/設定することもThreadできるため、メソッド内にあるものがわかりますThread

次のステップは、それほどクリーンではありませんが、より高速なシステム、System.Threading.ReaderWriterLockSlimを実装することです。これの良いところは、すべてのスレッドが同時に読み取ることができるが、書き込み時にすべてをブロックすることです。したがって、基本的には、書き込みのみをブロックしています。

また、ToListToArrayなどを行うときは参照型に注意してください。

void Main()
{
    var slist = new List<Chunk>();
    var chunk = new Chunk{Name="asdf"};
    slist.Add(chunk);
    var slist2 = slist.ToList();
    slist[0].Name = "asdf2";
    Console.WriteLine(slist[0].Name); // outputs: asdf2
    Console.WriteLine(slist2[0].Name); // outputs: asdf2
}

public class Chunk
{
    public string Name {get;set;}
}
于 2013-08-14T21:04:47.000 に答える