views:

66

answers:

5

I currently have a multithreaded application which runs in following order:

  1. Start up and change XML file
  2. Do work
  3. Change XML to default values

The step 3 is very important and I have to insure that it always happens. But if the application crashes, I might end up with the wrong XML.

The scenario where I am using it is:

My application is a small utility which connects to a remote device, but on the same machine there is a running service which is connected to the same remote device, which I want to connect to. Service exposes restartService method and during startup depending on the XML data it will connect to the remote device or will not. So in the end I have to ensure that whatever happened to my application, XML is set to the default state.

I thought having a thread running as a separate process and checking every n seconds if the main process is alive and responding would solve this issue. But I have found very few examples of multiprocess applications in C#. So if someone could show an example of how you to create a thread which runs as a separate process, that would be great.

What if I create a separate project - console application. It is compiled into separate executable and is launched from within main application. Then use IpcChannel for the communication between 2 processes. Or Create a WCF application. Will one of these approach work?

+2  A: 

A Thread belongs to a Process, so if the process dies then so do all it's threads. Each application is expected to be a single process and while you can launch additional processes it sounds like a complex solution to what might be a simple problem.

Rather than changing and reverting the file could you just read it into memory and leave the filesystem alone?

STW
No, I can't because it's a configuration file of a service which I am reading and depending on it service will perform one or another action. So I have to change it.
Vitalij
It seems like a simple problem, but I can't think of a simpler solution. As I have mentioned it is an absolute must to write to this file after application finished it's work.
Vitalij
A: 

What you are talking about is usually called "supervision" in mainframe computing and other large-ish computing infrastructures. A supervised process is a process that runs under the scrutiny of a supervisor process, which restarts it or otherwise "fixes" the problem if the former crashes or is unable to finish its job.

You can see a glimpse of this in the way that Windows restarts services automatically if they stop working; that is a very simplistic version of a supervision subsystem.

As far as I understand, this is a complex area of computer engineering, and I don't think that Windows or .NET provide a programmatic interface to it. Depending on your specific needs, you might be able to develop a simple approach to it.

CesarGon
+1  A: 

You can subscribe to an event called DispatcherUnhandledException so when ever an Unhandled exception is thrown , you can safely revert your XML settings.

 public partial class App : Application
{
    public App()
    {
        this.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
    }

    void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
    {
        //When ever an Unhandeled exception is thrown

        // You can change your XML files to default values.
    }

}

// If you killed process through Task Manager

AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);

void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        // Change your Settings Here.
    }

// If you initiated Windows ShutDown

this.SessionEnding += new SessionEndingCancelEventHandler(App_SessionEnding);

  void App_SessionEnding(object sender, SessionEndingCancelEventArgs e)
    {
        // XML Changes
    }
saurabh
That is a good approach, but what will happen if the application is killed?
Vitalij
added code for Killed Process as well as for windows Shutdown started , please subscribe to these evens in the constructor of App class.
saurabh
A: 

Consider setting a "dirty" flag in your config file and storing a backup of the default XML in another file. When your application starts it changes the XML and sets the flag. If it successfully completes then it resets the flag and restores the XML. Your service checks the flag to see if it needs to use the last XML written by your app or switch to the backup file.

ebpower
I can't modify service's code. I have an API which exposes restart method only. And the XML is read during the start up of the service.
Vitalij
Then you should consider a separate monitor service as you touched on in your question, and as was suggested by CesarGon, that keeps tabs on your app. You should be able to catch all exceptions thrown in your app and have a graceful exit, with your monitor watching for the edge cases. You can add further protection by having your app update a small status file or database table with a timestamp that your monitor watches and does a clean-up if the timestamp isn't updated periodically.
ebpower
A: 

I think that whether the application is multithreaded or multiprocess or whatever is not actually the problem you need to solve. The real problem is: how do I make this operation atomic?

When you say that you have to insure that step 3 always happens, what you're really saying is your program needs to perform an atomic transaction: either all of it happens, or none of it happens.

To accomplish this, your process should be designed the way that database transactions are designed. It should begin the transaction, do the work, and then either commit the transaction or roll it back. The process should be designed so that if, when it starts up, it detects that a transaction was begun and not committed or rolled back by an earlier run, it should start by rolling back that transaction.

Crucially, the commit method should have as little instability as possible. For instance, a typical way to design a transactional process is to use the file system: create a temporary file to indicate that the transaction has begun, write the output to temporary files, and then have the commit method rename the temporary files to their final names and delete the transaction-flag file. There's still a risk that the file system will go down in between the time you've renamed the files and the time you've deleted the flag file (and there are ways to mitigate that risk too), but it's a much smaller risk than the kind you've been describing.

If you design the process so that it implements the transactional model, whether it uses multiprocessing or multithreading or single-threading is just an implementation detail.

Robert Rossney