0

ローカル データベースにデータを保存する Windows Phone アプリを作成しています。私のアプリにはデータベースにアクセスする複数のスレッドがあり、この時点まで、AutoResetEvent を使用してここで説明した手法を使用して、一度に 1 つのスレッドのみがデータベースにアクセスできるようにしました。

これまでのところ、これは非常に確実に機能していますが、バックグラウンドでいくつかの作業を行うために ScheduledTask を追加したいので、複数のプロセスがデータベースへのアクセスで競合する可能性があります。

AutoResetEvent 手法を Windows Phone の複数のプロセスで使用できるようにする方法を教えてもらえますか?

Mutex を使用したアプローチを見てきました。各 DB 呼び出しの前に Mutex を取得し、後で解放すると (AutoResetEvent を使用しているのと同様に)、うまくいきますか? この手法に潜在的な問題はありますか? 例: パフォーマンス?

4

3 に答える 3

2

Windows Phone 8でBensソリューションを使用すると、いくつかの問題が発生しました。問題の完全なドキュメントについては、このスレッドを参照してください。

「Global\SingleInstanceSynchroniser」から「Global\」を削除することで問題を解決できました。

于 2013-01-22T07:03:27.490 に答える
2

わかりましたので、まず最初に私の問題は実際には2つの問題でした:

  1. フォアグラウンド アプリが実行されている場合、バックグラウンド プロセスが実行されないようにする必要があります。
  2. 一度に 1 つのスレッドのみがデータベースにアクセスできるようにする必要があります。これは、バックグラウンド プロセスの進行中にフォアグラウンド アプリが開始される (確かにまれですが、可能性があります) シナリオに対応するために、プロセス間で機能する必要があります。

このスレッドで行われた優れた作業に基づいて、役立つクラスをいくつか作成しました。

問題 (1) を解決するために、SingleInstanceSynchroniser を作成しました。

/// <summary>
/// Used to ensure only one instance (foreground app or background app) runs at once
/// </summary>
public class SingleInstanceSynchroniser : IDisposable
{
    private bool hasHandle = false;
    Mutex mutex;

    private void InitMutex()
    {
        string mutexId = "Global\\SingleInstanceSynchroniser"; 
        mutex = new Mutex(false, mutexId);
    }

    public SingleInstanceSynchroniser()
    {
        InitMutex();
        hasHandle = mutex.WaitOne(0);
    }

    public void Dispose()
    {
        if (hasHandle && mutex != null)
            mutex.ReleaseMutex();
    }

    public bool HasExclusiveHandle { get { return hasHandle; } }

}

使用法:

App.xaml.cs で:

...

SingleInstanceSynchroniser singleInstanceSynchroniser;

public App()
{
    singleInstanceSynchroniser = new SingleInstanceSynchroniser();

...

ScheduledAgent.cs で:

SingleInstanceSynchroniser singleInstanceSynchroniser;

protected override void OnInvoke(ScheduledTask task)
    {
        singleInstanceSynchroniser = new SingleInstanceSynchroniser();

        if (singleInstanceSynchroniser.HasExclusiveHandle)
        {
            //Run background process
            ...
        }
        else
        { //Do not run if foreground app is running
            NotifyComplete();
        }
    }

問題 (2) を解決するために、SingleAccessSynchroniser を作成しました。

/// <summary>
/// Used to ensure only one call is made to the database at once 
/// </summary>
public class SingleAccessSynchroniser : IDisposable
{
    public bool hasHandle = false;
    Mutex mutex;

    private void InitMutex()
    {
        string mutexId = "Global\\SingleAccessSynchroniser"; 
        mutex = new Mutex(false, mutexId);            
    }

    public SingleAccessSynchroniser() : this(0)
    { }

    public SingleAccessSynchroniser(int TimeOut)
    {
        InitMutex();

        if (TimeOut <= 0)
            hasHandle = mutex.WaitOne(); 
        else
            hasHandle = mutex.WaitOne(TimeOut);

        if (hasHandle == false)
            throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
    }

    public void Release()
    {
        if (hasHandle && mutex != null)
        {
            mutex.ReleaseMutex();
            hasHandle = false;
        }
    }

    public void Dispose()
    {
        Release();
    }
}

使用法: すべてのデータベース呼び出しで:

using (var dbSync = new SingleAccessSynchroniser())
        {
            //Execute your database calls
        }

これは、数週間にわたって確実に実行されています。他の誰かがそれが役に立つことを願っています。

于 2012-07-06T07:25:22.970 に答える
1

エージェントとアプリ間のデータベースへの同時アクセスは問題になりません。実際、Linq2SQL の使用は、アプリとエージェント間の通信に推奨される方法の1 つです。

実際には、アプリとエージェントを同時に実行する必要があることはめったにないため、そのようなことが起こらないようにする方が適切な場合があります。

潜在的なパフォーマンスの問題は、何をしているかによって異なります。本当に問題があるかどうかを確認するには、これを測定する必要があります。

于 2012-06-20T08:28:44.990 に答える