わかりましたので、まず最初に私の問題は実際には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
}
これは、数週間にわたって確実に実行されています。他の誰かがそれが役に立つことを願っています。