好的,首先我的问题实际上是两个问题:
- 需要确保如果前台应用程序正在运行,则后台进程不会运行
- 需要确保一次只有一个线程可以访问数据库,并且这需要跨进程工作,以适应(诚然很少见,但可能)在后台进程正在进行时启动前台应用程序的情况。
基于此线程中所做的出色工作,我创建了几个类来提供帮助。
为了解决问题(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
}
这已经可靠地运行了几个星期。希望别人觉得它有用。