4

c#のWindowsアプリケーションで独自のイベントシステムを作成したいと思います。これを行うために、私は次のクラスを書きます:

internal class EventManager
{
    private static List<EventRecord> s_listEvents = new List<EventRecord>();

    public static void AddEvent(EventRecord record)
    {
        record.EventDate = DateTime.Now;
        s_listEvents.Add(record);
    }

    public static List<EventRecord> GetRecordsByDate(DateTime date)
    {
        var r = (from l in s_listEvents
                 where l.EventDate >= date
                 select l).ToList<EventRecord>();
        return r;
    }
}

EventManagerクラスがスレッドセーフであることを確認したいと思います。アプリケーションで同時に数百のスレッドを作成するためです。ほとんどの場合、すべてのスレッドがこのクラスを使用してイベントを生成します。また、関数が別のスレッドから呼び出されるGetRecordsByDateときに、クラスの外部から関数が呼び出される場合があります。 簡単に言うと、この設計はマルチスレッドウィンドウアプリケーションに適していると言えますか?これがスレッドセーフでない場合、クラスまたはそのメンバーをスレッドセーフにするにはどうすればよいですか?同期オブジェクトを使用してクラス全体をロックする必要がありますか、それともreadwritelockerを使用して静的メンバーをロックする必要がありますか?AddEvent

EventManagers_listEvents

4

5 に答える 5

3

を使用する代わりにList<T>、を使用する必要がありますConcurrentBag<T>

ConcurrentBagはスレッドセーフなバッグの実装であり、同じスレッドがバッグに格納されているデータを生成および消費するシナリオ向けに最適化されています。

詳しくは:

http://msdn.microsoft.com/en-us/library/dd381779.aspx

また、アクセスするスレッドの数を作成するように注意してください。100を超えるスレッドは、コンテキストの切り替えに時間がかかるため、パフォーマンスが低下します。

編集: .NET 3.5の場合、単純なものを使用してスレッドセーフにすることができますlock

internal class EventManager
{
    private static List<EventRecord> s_listEvents = new List<EventRecord>();
    private static object _syncObject = new object();


    public static void AddEvent(EventRecord record)
    {
        record.EventDate = DateTime.Now;
        lock(_syncObject)
        {
           s_listEvents.Add(record); 
        }

    }

    public static List<EventRecord> GetRecordsByDate(DateTime date)
    {
        lock (_syncObject)
        {
             var r = (from l in s_listEvents
                 where l.EventDate >= date
                 select l).ToList<EventRecord>();

             return r;
        }

    }
}

編集

状況によっては、データを頻繁に読み取る場合は、複数のスレッドでデータを読み取ることができるため、アプリケーション全体でwithを使用ReaderWriterLockSlimする方が適切です。ReaderWriterLock

そうでない場合は、lock一般的にパフォーマンスが優れているものを使用してください。

リンクを参照してください:

http://blogs.msdn.com/b/pedram/archive/2007/10/07/a-performance-comparison-of-readerwriterlockslim-with-readerwriterlock.aspx

于 2012-10-01T09:05:15.363 に答える
2

クラスは静的であるため、s_listEventsメンバーをロックする必要があります。EventManager自体(または他の静的クラス)の静的メンバーとしてロックを使用可能にしない限り、呼び出し元が共有ロックオブジェクトにアクセスできない可能性が高くなります。この場合s_listEvents、EventManagerでアクセスのロックアラウンドを直接実装することもできます。このようにして、発信者がロックの取得を忘れるという問題を回避できます。

リーダー/ライターロックはこれに適しているようです。

于 2012-10-01T09:04:49.733 に答える
2

ReaderWriterLockクラスを使用できます。

internal class EventManager
{
    static ReaderWriterLock rwl = new ReaderWriterLock();

    private static List<EventRecord> s_listEvents = new List<EventRecord>();

    public static void AddEvent(EventRecord record)
    {
        record.EventDate = DateTime.Now;
        rwl.AcquireWriterLock(0);
        try
        {
            s_listEvents.Add(record);
        }
        finally
        {
            rwl.ReleaseWriterLock();
        }
    }

    public static List<EventRecord> GetRecordsByDate(DateTime date)
    {
        rwl.AcquireReaderLock(0);
        try
        {
            var r = (from l in s_listEvents
                     where l.EventDate >= date
                     select l).ToList<EventRecord>();
            return r;
        }
        finally
        {
            rwl.ReleaseReaderLock();
        }
    }
}
于 2012-10-01T09:14:22.230 に答える
1

次のリンクが役立ちます。

クラスをスレッドセーフにする方法

private object _lock;

public static void AddEvent(EventRecord record)
{
    lock (_lock)
    {
        record.EventDate = DateTime.Now;
        s_listEvents.Add(record);
    }
}
于 2012-10-01T09:14:46.457 に答える
1

質問に対する最も基本的な答えは次のとおりです。ソリューションをスレッドセーフにするには、データストレージを同時アクセスから保護する必要があります。これは、リストにアクセスしている任意の時点でリストをロックすることによって行われます。つまり、リストを繰り返し処理したり、リストに追加したり、リストから削除したりするときは、その領域をロックする必要があります。

その数のサーバーにアクセスしている場合でも、おそらく100以上のスレッドを生成したくないでしょう。代わりに、スレッドプールを使用することをお勧めします。http://msdn.microsoft.com/en-us/library/0ka9477y(v詳細については、 = vs.90).aspxを参照してください。これにより、説明しているような単純な「チェックイン-データのダウンロード-チェックアウト」タスクに使用するスレッドのプールが提供されます。

マルチスレッドアプリケーションを作成するときは、基盤となるストレージの使用パターンを考慮することが重要です。アプリケーションが1秒間に数百の追加を実行する場合は、日付でレコードを取得しようとするたびにシステム全体をブロックしない、基になるデータ構造の読み取り専用コピーを用意することを検討してください。詳細な紹介については、インテルの最適化ガイドを参照してください。

于 2012-10-01T09:30:08.917 に答える