0

I made a code that create a Database in .sqlite, all working good but I want to be sure that when the user start for the first time the application the Database population must be completed. If the user abort the database population, the database must be deleted (because the application don't working with an incomplete resource). Now I've used the thread for execute the method that create this Database, and I've declared the thread variable global in the class, like:

Thread t = new Thread(() => Database.createDB());

The Database.createDB() method create the DB. All working perfect, the DB is created correctly. Now I fire the closing of the window that creating the DB like:

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
    {
            MessageBoxResult result = MessageBox.Show(
                    @"Sure?",
                    "Attention", MessageBoxButton.YesNo, MessageBoxImage.Question);
            try
            {
                if (result == MessageBoxResult.Yes)
                {
                    t.Abort();

                    if (File.Exists("Database.sqlite"))
                    {
                        File.Delete("SoccerForecast.sqlite");
                        Process.GetCurrentProcess().Kill();
                    } ....

The event was fired correct and the thread stopped, but when the condition start if (File.Exists("Database.sqlite")) the compiler tell me:

Can't delete file - in using by another process.

But I've stopped the thread, why this exception appear? What I doing wrong?

UPDATE:

In CreateDb() method I also have a call to other method of different class, one of this have the structure like this:

public void setSoccer()
{
        Database.m_dbConnection.Open(); 
        string requestUrl = "...";
        string responseText = Parser.Request(requestUrl);
        List<SoccerSeason.RootObject> obj = JsonConvert.DeserializeObject<List<SoccerSeason.RootObject>>(responseText);

        foreach (var championships in obj)
        {
            string sql = "string content";
            SQLiteCommand command = new SQLiteCommand(sql, Database.m_dbConnection);
            try
            {
                command.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        string query = "select * from SoccerSeason";
        SQLiteCommand input = new SQLiteCommand(query, Database.m_dbConnection);
        SQLiteDataReader reader = input.ExecuteReader();

        int i = 0;
        while (reader.Read())
        {
            //reading data previously inserted in the database
        }
        Database.m_dbConnection.Close(); /
}

I was wondering where I should put the flag variable because this code have a different loop inside.

Harold Finch
  • 576
  • 11
  • 32
  • 5
    Aborting a thread is almost always the wrong thing to do. Find a more graceful way to let the thread know that it should exit, then allow it to do so cleanly (e.g. `ManualResetEvent` or something similar) – Damien_The_Unbeliever Jul 10 '15 at 09:42
  • Abort "forcefully terminates the affected thread even if it has not completed its task and provides no opportunity for the cleanup of resources." – Paul Zahra Jul 10 '15 at 10:06
  • 1
    Have a read of http://stackoverflow.com/questions/9272332/what-is-a-safe-way-to-stop-a-running-thread – Paul Zahra Jul 10 '15 at 10:06
  • Also read http://stackoverflow.com/questions/3632149/question-about-terminating-a-thread-cleanly-in-net it explains some of your major options. – Paul Zahra Jul 10 '15 at 10:11
  • Can you show me a little example of your idea? I'm interested on this, I are stuck for days on the problem, I tried with BackgroundWorker and now with the thread and I still failed – Harold Finch Jul 10 '15 at 10:16
  • Handles are held by the process, not the thread. Aborting a thread doesn't release handles opened by the thread. They will remain open until either the process terminates or a garbage collection occurs – Panagiotis Kanavos Jul 10 '15 at 10:40
  • I would say see if you can get the overall concept working first, then worry about optimising the cancellation speed, how many times is it likely to go through that foreach loop? Also, you could just put a flag on that setSoccer class that the thread cancellation handling sets. – Nanhydrin Jul 10 '15 at 10:56
  • That depends on the data in JSON, currently 10 times, but in the future may be 100 if not 1000, in fact we can not say exactly, is this a problem? – Harold Finch Jul 10 '15 at 11:06
  • Not a problem, just another thing to think about, as I say you could easily put a flag into that class as well that cancels out when the application is closing. But my point was does it really matter that much if the application might have to wait for a couple of seconds while something finishes before it closes? – Nanhydrin Jul 10 '15 at 12:57
  • This activity need time to create and valorize the DB. You could show me where pur this flag? Because how you can see I have two loop on this method and I don't know the part of code that's esecuted when the user stop – Harold Finch Jul 10 '15 at 13:27

1 Answers1

1

It could be that when you're aborting the thread it's not cleanly closing the database connections, hence the error you're seeing.

Might I suggest a slight redesign because using Thread.Abort is not ideal.
Instead use a variable as a cancel flag to notify the thread to shut down.
Then when the thread detects that this cancel flag is set it can properly close connections and handle the database delete itself.

Update:
A brief example to illustrate what I mean; it ain't pretty and it won't compile but it gives the general idea.

public class Database
{
    public volatile bool Stop= false;

    public void CreateDb()
    {
        if(!Stop)
        {
           // Create database 
        }

        if(!Stop)
        {
           // Open database
           // Do stuff with database
        }

        // blah blah ...

        if(Stop)
        {
           // Close your connections
           // Delete your database
        }
    }
}

...

    protected override void OnClosing(CancelEventArgs e)
    {
        Database.Stop = true;
    }

And now that you know roughly what you're looking for I heartily recommend Googling for posts on thread cancellation by people who know what they're talking about that can tell you how to do it right.

These might be reasonable starting points:
How to: Create and Terminate Threads
.NET 4.0+ actually has a CancellationToken object with this very purpose in mind Cancellation in Managed Threads

Community
  • 1
  • 1
Nanhydrin
  • 4,332
  • 2
  • 38
  • 51
  • A bit problem is that I've other method of different class in CreateDb(); this method having a foreach .. I should put this condition "stop" in the foreach? – Harold Finch Jul 10 '15 at 10:25
  • Possibly yes. It would be easier to say if you edit your question and add some of the CreateDb() code though. – Nanhydrin Jul 10 '15 at 10:26
  • Okay, I've update the question with the structure of the methods that I've. If you can take a look. Thanks for the help. I've really appreciate. – Harold Finch Jul 10 '15 at 10:36
  • It may not be necessary to be able to cancel out of that inner method really if it runs very quickly. I would say see if you can get the overall concept working first, then worry about optimising the cancellation speed. Also, you could just put a flag on that setSoccer class that the thread cancellation handling sets. – Nanhydrin Jul 10 '15 at 10:43
  • That depends on the data in JSON, currently 10 times, but in the future may be 100 if not 1000, in fact we can not say exactly, is this a problem? – Harold Finch Jul 10 '15 at 11:42