Windows Phone中对数据库的多进程访问

时间:2012-06-18 09:04:36

标签: c# multithreading windows-phone-7

我正在编写一个将数据存储在本地数据库中的Windows手机应用程序。我的应用程序中有多个线程访问数据库,直到此时我使用了here描述的技术和AutoResetEvent,以确保一次只有一个线程可以访问数据库。

到目前为止,这已经非常可靠,但是现在我想添加一个ScheduledTask来在后台完成一些工作,所以我现在可能有多个进程竞争访问数据库。

任何人都可以建议我如何调整AutoResetEvent技术以在Windows Phone上的多个进程中使用?

我见过使用Mutex的方法。如果我在每个数据库调用之前获取Mutex然后在之后释放它(类似于我使用AutoResetEvent的方式),这会起作用吗?这种技术有任何潜在的问题吗?例如:表现?

3 个答案:

答案 0 :(得分:2)

好的,首先我的问题实际上是2个问题:

  1. 需要确保如果前台应用程序正在运行,后台进程将无法运行
  2. 需要确保只有一个线程可以同时访问数据库,这需要跨进程工作,以满足前台应用程序在后台进程正在进行时启动的前提应用程序(当然很少但可能)。
  3. 基于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之一。

在实践中,应用和代理很少需要同时运行,因此可能更适合防止这种情况发生。

潜在的性能问题取决于您正在做什么。您需要对此进行测量以确定它是否真的存在问题。