2012-06-18 17 views
0

我正在寫一個Windows Phone應用程序,它將數據存儲在本地數據庫中。我的應用程序中有多個線程訪問數據庫,直到這一點,我已經使用了描述here的AutoResetEvent技術來確保一次只有一個線程可以訪問數據庫。在Windows Phone中多進程訪問數據庫

到目前爲止,這工作非常可靠,但現在我想添加一個ScheduledTask在後臺執行一些工作,所以我可能已經有多個進程競爭訪問數據庫。

任何人都可以告訴我如何適應在Windows Phone上的多個進程中使用AutoResetEvent技術?

我見過使用互斥鎖的方法。如果我在每次數據庫調用之前獲取互斥鎖,然後再釋放它(類似於我使用AutoResetEvent的方式),這是否有用?這種技術有什麼潛在的問題嗎?例如:表演?

回答

2

好了,所以首先我的問題實際上是兩個問題:

  1. 需要確保,如果前臺應用程序正在運行,後臺進程將不會運行
  2. 需要確保只有一個線程可以立即訪問數據庫,並且這需要在各個流程中工作,以迎合後臺進程正在啓動時前臺應用程序啓動的情況(公認罕見但可能)。

基於在this thread所做的出色工作,我創建了幾個課程來提供幫助。

爲了解決問題(1),I創建的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

併發訪問代理和應用程序之間的數據庫不應該是一個問題。實際上,使用Linq2SQL是其中的一個recommended ways for communicating between the app and agent

實際上,應用程序和代理很少需要同時運行,因此可能更適合防止發生這種情況。

潛在的性能問題將取決於你在做什麼。您需要對此進行衡量,看看是否真的存在問題。

+0

如果在前臺應用兩個線程使同時數據庫請求,那麼你得到這些錯誤之一:「因爲在另一個線程的操作尚未完成無法執行操作」 出現InvalidOperationException 出現InvalidOperationException 「在調用SubmitChanges期間無法執行此操作。」 我不明白爲什麼在後臺應用程序試圖訪問數據庫時這會有所不同,因此您的併發訪問不應該成爲問題的意見是一點點混亂? 我找到了解決這個問題的辦法。當我得到一個空閒時間,我會張貼在這裏:) –

2

我在Windows Phone 8上使用Bens解決方案時遇到了一些問題。請參閱this線程獲取有關這些問題的完整文檔。

我能夠通過從「Global \ SingleInstanceSynchroniser」中刪除「Global \」來解決問題。