我正在编写一个将数据存储在本地数据库中的Windows手机应用程序。我的应用程序中有多个线程访问数据库,直到此时我使用了here描述的技术和AutoResetEvent,以确保一次只有一个线程可以访问数据库。
到目前为止,这已经非常可靠,但是现在我想添加一个ScheduledTask来在后台完成一些工作,所以我现在可能有多个进程竞争访问数据库。
任何人都可以建议我如何调整AutoResetEvent技术以在Windows Phone上的多个进程中使用?
我见过使用Mutex的方法。如果我在每个数据库调用之前获取Mutex然后在之后释放它(类似于我使用AutoResetEvent的方式),这会起作用吗?这种技术有任何潜在的问题吗?例如:表现?
答案 0 :(得分:2)
好的,首先我的问题实际上是2个问题:
基于this thread所做的出色工作,我创建了几个类来帮助。
为了解决问题(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
}
这已经运行了几个星期了。希望别人觉得它有用。
答案 1 :(得分:2)
我在Windows Phone 8上使用Bens解决方案时遇到了一些问题。请参阅this主题以获取问题的完整文档。
我可以通过从“Global \ SingleInstanceSynchroniser”中删除“Global \”来解决问题。
答案 2 :(得分:1)
代理和应用程序之间的数据库并发访问应该不是问题。实际上,使用Linq2SQL是recommended ways for communicating between the app and agent之一。
在实践中,应用和代理很少需要同时运行,因此可能更适合防止这种情况发生。
潜在的性能问题取决于您正在做什么。您需要对此进行测量以确定它是否真的存在问题。