Multi-process access to database in Windows Phone - c#

I'm writing a windows phone app which stores data in a local database. There are multiple threads in my app that access the database and up until this point I have used the technique described here with an AutoResetEvent to ensure that only one thread can access the database at any one time.
So far this has worked very reliably, but now I want to add a ScheduledTask to do some work in the background so I've potentially got multiple processes now competing for access to the database.
Can anyone advise how I can adapt the AutoResetEvent technique to be used across multiple processes on Windows Phone?
I have seen approaches using a Mutex. If I acquire the Mutex before each DB call and then release it afterwards (similar to the way I'm using AutoResetEvent), will this do the trick? Is there any potential problems with this technique? eg: performance?

Ok so first of all my problem was actually 2 problems:
Need to ensure that if the foreground app is running, the background process won't run
Need to ensure that only one thread can access the databasse at once and this needs to work across processes to cater for the (admittedly rare, but possible) scenario where the foreground app is started while the background process is in progress.
Based on the good work done in this thread, I created a couple of classes to help.
To solve problem (1), I created the 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; } }
}
Usage:
In App.xaml.cs:
...
SingleInstanceSynchroniser singleInstanceSynchroniser;
public App()
{
singleInstanceSynchroniser = new SingleInstanceSynchroniser();
...
In 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();
}
}
To solve problem (2), I created the 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();
}
}
Usage: In all database calls:
using (var dbSync = new SingleAccessSynchroniser())
{
//Execute your database calls
}
This has been running reliably for a few weeks now. Hope someone else finds it useful.

I ran into some problems using Bens solution on Windows Phone 8. Please see this thread for a complete documentation of the problems.
I was able to resolve the issues by removing "Global\" from "Global\SingleInstanceSynchroniser".

Concurrent access to a database between an agent and an app shouldn't be an issue. In fact, using Linq2SQL is one of the recommended ways for communicating between the app and agent.
In practice, it's rarely necessary for the app and agent to run at the same time and so it may be more appropriate to prevent that happening instead.
Potential performance issues will be dependent upon what you're doing. You'll need to measure this to see if it's really an issue.

Related

Pythonnet how to stop script execution properly

I'm using Pythonnet to embed a Python script launcher into a C# WPF application. I can pass variable to python scripts using Scope and i get the result on a console using MVVM pattern.
Now I want to allow the user to stop a script execution at anytime. I couldn't find how to make that work in order to close the Thread properly.
class PythonRuntime
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private MainViewModel viewModel;
private string pythonCode;
private bool runtimeThreadLock = false;
Thread thread;
private PyScope scope;
private dynamic pyThread;
private dynamic pyLock;
ConsoleWriter consoleWriter;
public PythonRuntime(MainViewModel viewModel, ConsoleWriter consoleWriter)
{
this.viewModel = viewModel;
this.consoleWriter = consoleWriter;
SetUpPython();
}
public string PythonCode { get => pythonCode; set => pythonCode = value; }
private void SetUpPython()
{
PythonEngine.Initialize(true);
scope = Py.CreateScope();
// consoleWriter to make python prints into C# UI
scope.Set("Console", consoleWriter);
}
public void LaunchScript()
{
if (!runtimeThreadLock)
{
thread = new Thread(PythonNetTest);
thread.Start();
}
}
public void StopScript()
{
// ???
}
[HandleProcessCorruptedStateExceptions]
private void PythonNetTest()
{
runtimeThreadLock = true;
pyThread = PythonEngine.BeginAllowThreads();
pyLock = PythonEngine.AcquireLock();
using (Py.GIL())
{
try
{
scope.Exec(pythonCode);
}
catch (PythonException exception)
{
consoleWriter.WriteError(exception.ToString());
}
}
PythonEngine.ReleaseLock(pyLock);
PythonEngine.EndAllowThreads(pyThread);
runtimeThreadLock = false;
}
}
Besides my question, I was wondering what is the purpose of wrapping code in using(Py.GIL()). Because with or whithout it my script runs the same way.
Pythonnet : 2.4.0
Python : 2.7.2 32bit
NetFramework : 4.7.1
OK, I'm just beginning work on embedding CPython and may know only a little more than you. What that caveat...
First, you need to get your script to terminate. When it does the call to .Exec() will return, and the thread will exit. If your script runs for a finite amount of time then you just wait for it. Otherwise, you must arrange some signal that it should exit.
Second, mainline will wait for thread to complete using one of several .NET patterns described at: How to wait for thread to finish with .NET?
using(Py.GIL()) is shorthand for PythonEngine.AcquireLock(); and PythonEngine.ReleaseLock(pyLock); It creates an IDisposable object that acquires the lock and then releases it on Dispose(). So, in your sample, it is redundant.
I'm unsure effects of your call to BeginAllowThreads(). Documentation says that it releases the lock to allow other threads. When you call it you don't have the GIL. Next line acquires the GIL. Therefore, it appears to have no function to me.
See https://docs.python.org/3/c-api/init.html for details on threading. This seems more related to python threading and saving thread state so that other non-python things can be done. This is python 3. Python 2 did not seem to support the equivalent.

C# allowing one thread to run the method at a time after multiple requests triggerred to application server

I am building an ASP.NET web.api service. there is api needs more than 2 minutes to retrieve desired data, so I implemented cache mechanism, and every request sent to API Server, the server will return the cached data and meanwhile start a new thread to load new data into the cache, the issue is if I submitted a lot of requests, a lot of thread will be running and eventually crashed the server, I want to implement a mechanism to control only a thread at any certain time, but I know ASP.NET Web.API is inherently multi threads, how do I tell other request to wait, because there is one thread already retrieving new set of data ?
[Dependency]
public ICacheManager<OrderArray> orderArrayCache { get; set; }
private ReadOrderService Service = new ReadOrderService();
private const string _ckey = "all";
public dynamic Get()
{
try
{
OrderArray cache = orderArrayCache.Get(_ckey);
if(cache == null || cache.orders.Length == 0)
{
OrderArray data = Service.GetAllOrders();
orderArrayCache.Add(_ckey, data);
return data;
}
else
{
Caching();
return cache;
}
}
catch (Exception error)
{
ErrorLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, error.ToString());
return 0;
}
}
public void Caching()
{
Thread worker = new Thread(() => CacheWorker());
worker.Start();
}
public void CacheWorker()
{
try
{
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, "Cache Worker Is Starting to Work");
OrderArray data = Service.GetAllOrders();
orderArrayCache.Put(_ckey, data);
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, "Cache Worker Is Working Hard");
}
catch(Exception error)
{
//ActivityLog.WriteLog(Config._SystemName, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name, error.ToString());
}
}
Without commenting on the overall architecture, it's as trivial as setting a flag that you're working, and not starting the thread if that flag is set.
Of course in the ASP.NET MVC/WebAPI context, a controller instance is created for every request, so a simple field won't work. You could make it static, but that'll only work per AppDomain: one application can run in multiple AppDomains, by using multiple worker processes.
You could solve that by using a mutex, but then your application could be in a server farm, introducing a whole shebang of new problems.
That being said, the naive, static approach:
private static bool _currentlyRetrievingCacheableData = false;
public void Caching()
{
if (_currentlyRetrievingCacheableData)
{
return;
}
Thread worker = new Thread(() => CacheWorker());
worker.Start();
}
public void CacheWorker()
{
try
{
_currentlyRetrievingCacheableData = true;
// ...
}
catch(Exception error)
{
// ...
}
finally
{
_currentlyRetrievingCacheableData = false;
}
}
There's still a race issue here, but at most two threads can be accessing the CacheWorker() method. You can prevent that by using a lock statement.
Do note that all of this are workarounds for doing the obvious: let the cache refreshing mechanism live outside your web application code, for example in a Windows Service or a Scheduled Task.

How to prevent doubled timer in Global.asax?

Description:
On a C# ASP.Net web application, we have implemented some timers to periodically run background tasks. One of the timers occasionally seems to get "doubled" or more rarely "tripled".
The timer is set to run once every minute and seems to run properly for a while. Eventually, however, it seems like a second timer gets started and calls the timed process a second time within the same time interval. I've even seen a case where we had three processes running.
Since this process locks some database records and having a second (or third) process doing the same thing will cause a deadlock or timeout error on the database connection, we've implemented a mechanism to only allow one thread at a time to execute the database critical portion of the process code. When the process takes longer than a minute to run, this mechanism successfully blocks the next run triggered by its own timer. But the thread locking fails if the process is triggered by the second (or third) timer.
In our logs, I output both the Process ID and the Managed Thread ID, which lets me see which thread is starting, finishing, or erring out. The strange thing, is that regardless of which timer instance kicked off the process, the Process ID is the same.
var processID = System.Diagnostics.Process.GetCurrentProcess().Id;
var thread = System.Threading.Thread.CurrentThread.ManagedThreadId;
How do I prevent multiple instances of the timer?
We have a web-farm with 2 servers behind a load balancer. I've been assurred that the web-garden is set to only allow one instance of the app-pool on each server. A web.config setting specifies which server will run the timed process. The other server will not load the timer.
Relevant Code:
On the Global.asax.cs
protected static WebTaskScheduler PersonGroupUpdateScheduler
{
get;
private set;
}
protected void StartSchedulers()
{
using (var logger = new LogManager())
{
// ... other timers configured in similar fashion ...
if (AppSetting.ContinuousPersonGroupUpdates)
{
// clear out-of-date person-group-updater lock
logger.AppData.Remove("PersonGroupUpdater"); // database record to prevent interference with another process outside the web application.
var currentServer = System.Windows.Forms.SystemInformation.ComputerName;
if (currentServer.EqualsIngoreCase(AppSetting.ContinuousPersonGroupUpdateServer))
{
PersonGroupUpdateScheduler = new WebTaskScheduler() {
AutoReset = true,
Enabled = true,
Interval = AppSetting.ContinuousPersonGroupUpdateInterval.TotalMilliseconds,
SynchronizingObject = null,
};
PersonGroupUpdateScheduler.Elapsed += new ElapsedEventHandler(DistributePersonGroupProcessing);
PersonGroupUpdateScheduler.Start();
HostingEnvironment.RegisterObject(PersonGroupUpdateScheduler);
logger.Save(Log.Types.Info, "Starting Continuous Person-Group Updating Timer.", "Web");
}
else
{
logger.Save(Log.Types.Info, string.Format("Person-Group Updating set to run on server {0}.", AppSetting.ContinuousPersonGroupUpdateServer), "Web");
}
}
else
{
logger.Save(Log.Types.Info, "Person-Group Updating is turned off.", "Web");
}
}
}
private void DistributePersonGroupProcessing(object state, ElapsedEventArgs eventArgs)
{
// to start with a clean connection, create a new data context (part of default constructor)
// with each call.
using (var groupUpdater = new GroupManager())
{
groupUpdater.HttpContext = HttpContext.Current;
groupUpdater.ContinuousGroupUpdate(state, eventArgs);
}
}
On a separate file, we have the WebTaskScheduler class which just wraps System.Timers.Timer and implements the IRegisteredObject interface so that IIS will recognize the triggered process as something it needs to deal with when shutting down.
public class WebTaskScheduler : Timer, IRegisteredObject
{
private Action _action = null;
public Action Action
{
get
{
return _action;
}
set
{
_action = value;
}
}
private readonly WebTaskHost _webTaskHost = new WebTaskHost();
public WebTaskScheduler()
{
}
public void Stop(bool immediate)
{
this.Stop();
_action = null;
}
}
Finally, the locking mechanism for the critical section of the code.
public void ContinuousGroupUpdate(object state, System.Timers.ElapsedEventArgs eventArgs)
{
var pgUpdateLock = PersonGroupUpdaterLock.Instance;
try
{
if (0 == Interlocked.Exchange(ref pgUpdateLock.LockCounter, 1))
{
if (LogManager.AppData["GroupImporter"] == "Running")
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.Save(Log.Types.Info, string.Format("Group Import is running, exiting Person-Group Updater. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
return;
}
try
{
LogManager.Save(Log.Types.Info, string.Format("Continuous Person-Group Update is Starting. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
LogManager.AppData["PersonGroupUpdater"] = "Running";
// ... prep work is done here ...
try
{
// ... real work is done here ...
LogManager.Save(Log.Types.Info, "Continuous Person-Group Update is Complete", "Person-Group Updater");
}
catch (Exception ex)
{
ex.Data["Continuous Person-Group Update Activity"] = "Processing Groups";
ex.Data["Current Record when failure occurred"] = currentGroup ?? string.Empty;
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
}
catch (Exception ex)
{
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
finally
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.AppData.Remove("PersonGroupUpdater");
}
}
else
{
// exit if another thread is already running this method
LogManager.Save(Log.Types.Info, string.Format("Continuous Person-Group Update is already running, exiting Person-Group Updater. Person-Group Update Signaled at {0:HH:mm:ss.fff}.", eventArgs.SignalTime), "Person-Group Updater");
}
}
catch (Exception ex)
{
Interlocked.Exchange(ref pgUpdateLock.LockCounter, 0);
LogManager.Save(Log.Types.Error, ex, "Person-Group Updater");
}
}
IIS can/will host multiple AppDomains under a worker process (w3wp). These AppDomains can't/don't/shouldn't really talk to each. It's IIS's responsibility to manage them.
I suspect what's happening is that you have multiple AppDomains loaded.
That said...just to be 100% sure...the timer is being started under Application_Start in your global.asax, correct? This will get executed once per AppDomain (not per HttpApplication, as it's name suggests).
You can check how many app domains are running for your process by using the ApplicationManager's GetRunningApplications() and get GetAppDomain(string id) methods.
In theory you could also do some inter-appdomain communication in there to make sure your process only starts once...but I'd strongly advise against it. In general, relying on scheduling from a web application is ill advised (because your code is meant to be ignorant of how IIS manages your application lifetime).
The preferred/recommended approach for scheduling is via a Windows Service.

How do i stop the The database file is locked exception?

I have a multithreaded app that uses sqlite. When two threads try to update the db at once i get the exception
Additional information: The database file is locked
I thought it would retry in a few milliseconds. My querys arent complex. The most complex one (which happens frequently) is update, select, run trivial code update/delete, commit. Why does it throw the exception? How can i make it retry a few times before throwing an exception?
SQLite isn't thread safe for access, which is why you get this error message.
You should synchronize the access to the database (create an object, and "lock" it) whenever you go to update. This will cause the second thread to block and wait until the first thread's update finishes automatically.
try to make your transaction / commit blocks as short as possible. The only time you can deadlock/block is with a transaction -- thus if you don't do them you won't have the problem.
That said, there are times when you need to do transactions (mostly on data updates), but don't do them while you are "run trivial code" if you can avoid it.
A better approach may be to use an update queue, if you can do the database updates out of line with the rest of your code. For example, you could do something like:
m_updateQueue.Add(()=>InsertOrder(o));
Then you could have a dedicated update thread that processed the queue.
That code would look similar to this (I haven't compiled or tested it):
class UpdateQueue : IDisposable
{
private object m_lockObj;
private Queue<Action> m_queue;
private volatile bool m_shutdown;
private Thread m_thread;
public UpdateQueue()
{
m_lockObj = new Object();
m_queue = new Queue<Action>();
m_thread = new Thread(ThreadLoop);
m_thread.Start();
}
public void Add(Action a)
{
lock(m_lockObj)
{
m_queue.Enqueue(a);
Monitor.Pulse(m_lockObj);
}
}
public void Dispose()
{
if (m_thread != null)
{
m_shutdown = true;
Monitor.PulseAll(m_lockObj);
m_thread.Join();
m_thread = null;
}
}
private void ThreadLoop()
{
while (! m_shutdown)
{
Action a;
lock (m_lockObj)
{
if (m_queue.Count == 0)
{
Monitor.Wait(m_lockObj);
}
if (m_shutdown)
{
return;
}
a = m_queuue.Dequeue();
}
a();
}
}
}
Or, you could use something other than Sql Lite.

Restrict multiple instances of an application

Okay, so i've created my c# application, created an installer for it and have it working installed on my machine.
The problem is, when the user opens the application exe twice, there will be two instances of the application running. I only ever want one instance of the application to be running at any time, how do I go about doing this?
Thanks for your help,
The common technique for this is to create a named Mutex and check for its presence on application start.
See this or this.
Code from DDJ:
class App : Form
{
Mutex mutex;
App()
{
Text = "Single Instance!";
mutex = new Mutex(false, "SINGLE_INSTANCE_MUTEX");
if (!mutex.WaitOne(0, false))
{
mutex.Close();
mutex = null;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
mutex.ReleaseMutex();
base.Dispose(disposing);
}
static void Main()
{
App app = new App();
if (app.mutex != null) Application.Run(app);
else MessageBox.Show("Instance already running");
}
}
i solved this problem by this
[STAThread]
static void Main()
{
Process[] result = Process.GetProcessesByName("ApplicationName");
if (result.Length > 1)
{
MessageBox.Show("There is already a instance running.", "Information");
System.Environment.Exit(0);
}
// here normal start
}
it is simple, but i had hardly time to check for better solutions.
With thanks to Messrs. Allen and Powell:
static void Main()
{
using (Mutex mutex = new Mutex(false, #"Global\" + appGuid)) {
if (!mutex.WaitOne(0, false)) {
string processName = GetProcessName();
BringOldInstanceToFront(processName);
}
else {
GC.Collect();
Application.Run(new Voting());
}
}
}
private static void BringOldInstanceToFront(string processName) {
Process[] RunningProcesses = Process.GetProcessesByName(processName);
if (RunningProcesses.Length > 0) {
Process runningProcess = RunningProcesses[0];
if (runningProcess != null) {
IntPtr mainWindowHandle = runningProcess.MainWindowHandle;
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_SHOWMINIMIZED);
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_RESTORE);
}
}
}
I don't know the environment that you are operating in, but something to keep in mind about 'single-instance applications' is how you define single-instance. If the application can be run on multiple workstations at the same time, using a common datasource, is that an issue? Likewise, what about a terminal-services situation (or a "run as" situation) where more than one user is logged into the same computer, do you want to restrict the application in such a way that only one instance per-user, per-computer? Or are you okay with it simply being one instance per user?
The answer to these might lead you in one direction over another. For example, we have a 'single-instance' application with the scope being a group of computers. Only one user is allowed on within that group of workstations. We managed this by have a table in our shared data-source that tracked currently connected users. This is a maintenance issue as you need to be sure that table is 100% accurate all the time. Handling things like unexpected power outages on the workstation, leaving "bogus" records in that table took some careful handling.

Categories

Resources