5

.NET + EF アプリケーションを作成しました。すべてが単一のスレッドで正常に動作します。複数のスレッドでは、別の話です。

私の EF オブジェクトには、整数カウンターがあります。このプロパティは、"Concurrency Mode = Fixed" としてマークされています。基本的に、私がやろうとしているのは、複数のスレッドでこのカウンターを更新することです。この操作のように:

this.MyCounter -= 1;

同時実行モードが「固定」に変更されたため、既に変更されているプロパティを更新しようとすると、OptimisticConcurrencyExceptionがスローされます。

この同時実行の問題を解決するために、次のコードを使用しています。

while (true)
{
    try
    {
        this.UsageAmount -= 1; // Change the local EF object value and call SaveChanges().
        break;
    }
    catch (OptimisticConcurrencyException)
    {
        Logger.Output(LoggerLevel.Trace, this, "concurrency conflict detected.");
        EntityContainer.Instance.Entities.Refresh(RefreshMode.StoreWins, this.InnerObject);
    }
}

このコードの結果は、無限 (またはおそらくそのように見える) ループになります。this.UsageAmount -= 1throw を呼び出すたびにOptimisticConcurrencyException、ループが再度実行されます。

MyEntityContainer.Instance.Entitiesは、EF コンテキスト PER THREAD を提供するシングルトン クラスです。これは、すべてのスレッドが固有のコンテキストを持つことを意味します。コード:

public sealed class EntityContainer
    {
        #region Singlethon Implemantation
        private static Dictionary<Thread, EntityContainer> _instance = new Dictionary<Thread,EntityContainer> ();
        private static object syncRoot = new Object();
        public static EntityContainer Instance
        {
            get
            {
                if (!_instance.ContainsKey(Thread.CurrentThread))
                {
                    lock (syncRoot)
                    {
                        if (!_instance.ContainsKey(Thread.CurrentThread))
                            _instance.Add(Thread.CurrentThread, new EntityContainer());
                    }
                }
                return _instance[Thread.CurrentThread];
            }
        }
        private EntityContainer()
        {
            Entities = new anticopyEntities2();
        }
        #endregion

        anticopyEntities2 _entities;
        public anticopyEntities2 Entities
        {
            get
            {
                //return new anticopyEntities2();
                return _entities;
            }
            private set
            {
                _entities = value;
            }
        }
    }

ところで、Entities.Refreshメソッドを呼び出した後、動作しているように見えます (オブジェクトの状態は Unchanged であり、プロパティ値はデータベースに存在するものとまったく同じです)。

この並行性の問題を解決するにはどうすればよいですか?

4

1 に答える 1

1

データベースに保存したセマフォを使用して、複数インスタンスの Azure Webrole 用に記述したコードでこれを解決しました。セマフォを取得するために使用するコードは次のとおりです。競合するインスタンス間で発生する競合状態を処理するために、コードを追加する必要がありました。また、何らかのエラーが原因でセマフォがロックされたままになる場合に備えて、タイム リリースも追加します。

        var semaphore = SemaphoreRepository.FetchMySemaphore(myContext);
        var past = DateTime.UtcNow.AddHours(-1);

        //check lock, break if in use.  Ignor if the lock is stale.
        if (semaphore == null || (semaphore.InUse && (semaphore.ModifiedDate.HasValue && semaphore.ModifiedDate > past)))
        {
            return;
        }

        //Update semaphore to hold lock
        try
        {
            semaphore.InUse = true;
            semaphore.OverrideAuditing = true;
            semaphore.ModifiedDate = DateTime.UtcNow;
            myContext.Entry(semaphore).State = EntityState.Modified;
            myContext.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {
            //concurrency exception handeling another thread beat us in the race.  exit
            return;
        }
        catch (DBConcurrencyException)
        {
            return;
        }

        //Do work here ...  

私のセマフォモデルは次のようになります。

using System.ComponentModel.DataAnnotations;

public class Semaphore : MyEntityBase //contains audit properties
{

    [Required]
    [ConcurrencyCheck]
    public bool InUse { get; set; }

    public string Description { get; set; }
}
于 2012-12-18T13:26:12.500 に答える