Webapache
Webapache

Reputation: 97

C# WPF Thread Monitoring (If All Created Threads has Ended)

I'm a bit new to C# and WPF with my Project. Small picture of what i'm doing in the past. I wrote a Programm that does a backup of my MS SQL Databases. The idea was, to start every backup process in it's own process thread. That worked perfect! I start the process and thread by using:

...
string db_name = Convert.ToString(dataReader.GetValue(0));
var t = new Thread(() => BackupProcess(ServerName, SQLinstance, BackupPath, db_name));
t.Start();

Now, when all comes to an end, i would like to Monitor like "If the last thread comes to end, than do something like XY" What is the best way do this? THX for answering

Upvotes: 2

Views: 231

Answers (3)

Webapache
Webapache

Reputation: 97

Ok, i do not really understand the way it goes. As you can see, i'm going to start a new Task inside my Loop at Point: "while (dataReader.Read())". As much databases as i have in my Server, the Loop will repeat. I don't know how many DB's i will have in the next time. At the end, when ALL Tasks are finished, i would like to go to the "DoSomething" Method. Is there anybody who can tell me the way it goes. It makes me crazy (this stuff). :-)

    private async void ReadDatabase()
    {
        string errorMSG01 = "...";
        string errorMSG02 = "...";
        string captionMSG = "...

        string BackupPath = txtBakPath.Text;
        string ServerName = txtSqlServer.Text;
        string SQLinstance = cmbSqlInst.SelectedItem.ToString();

        MessageBoxButtons buttons = MessageBoxButtons.OK;

        if (String.IsNullOrEmpty(txtBakPath.Text))
        {
            System.Windows.Forms.MessageBox.Show(errorMSG01, captionMSG, buttons, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }
        else if (!Directory.Exists(BackupPath))
        {
            System.Windows.Forms.MessageBox.Show(errorMSG02, captionMSG, buttons, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
        }
        else
        {
            string connetionString = null;
            SqlConnection connection;
            SqlCommand command;
            string sql = null;
            SqlDataReader dataReader;
            connetionString = ("Data Source=DPC-OHEINRICH\\NETZWERKLABOR; Integrated Security=True;");
            sql = "Select * from Sys.Databases";
            connection = new SqlConnection(connetionString);
            try
            {
                connection.Open();
                command = new SqlCommand(sql, connection);
                dataReader = command.ExecuteReader();
                StatusPrinter(0x0003, null);
                CreateLogfile(BackupPath);
                DeleteOldBakFiles();
                while (dataReader.Read())
                {
                    string db_name = Convert.ToString(dataReader.GetValue(0));
                    Task backupTask = Task.Run(() => BackupProcess(ServerName, SQLinstance, BackupPath, db_name));
                }
                dataReader.Close();
                command.Dispose();
                connection.Close();
            }
            catch (Exception ex)
            {
                lblStatusMessage.Content = Convert.ToString(ex.Message);
            }
        }
    }

    private void BackupProcess(string ServerName, string SQLinstance, string BackupPath, string db_name)
    {
        DateTime today = DateTime.Now;
        string todayformat = string.Format("{0:G}", today);
        string BakFileDate = todayformat.Replace(".", "").Replace(" ", "").Replace(":", "");
        string ReportBakFile = BackupPath + "\\" + db_name + "_db_" + BakFileDate + @".bak'";

        if (db_name != "tempdb")
        {
            string connetionString = null;
            SqlConnection connection;
            SqlCommand command;
            string sql = null;
            SqlDataReader dataReader;
            connetionString = ("Data Source="+ServerName+"\\"+SQLinstance+"; Integrated Security=True;");
            sql = @"BACKUP DATABASE " + db_name + @" TO DISK = '" + BackupPath + "\\" + db_name + "_db_" + BakFileDate + @".bak'";
            connection = new SqlConnection(connetionString);
            try
            {
                connection.Open();
                command = new SqlCommand(sql, connection);
                dataReader = command.ExecuteReader();
                dataReader.Close();
                command.Dispose();
                connection.Close();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.Message);
            }
            this.Dispatcher.Invoke(new Action(() => this.WriteLogile(1, ReportBakFile)));
            this.Dispatcher.Invoke(new Action(() => this.StatusPrinter(0x0004, db_name)));
        }
    }
    public void DoSomething()
    {
        //we are done...
    }

Upvotes: 0

flayn
flayn

Reputation: 5322

Have a look at the TPL and the ContinueWith. It's very elegant and should match your requirements.

Action<string> action =
            (str) =>
                Console.WriteLine("Task={0}, str={1}, Thread={2}", Task.CurrentId, str, Thread.CurrentThread.ManagedThreadId);

// Creating a sequence of action tasks (that return no result).
Console.WriteLine("Creating a sequence of action tasks (that return no result)");
Task.Factory.StartNew(() => action("alpha"))
            .ContinueWith(antecendent => action("beta"))        // Antecedent data is ignored
            .ContinueWith(antecendent => action("gamma"))
            .Wait();

from: https://msdn.microsoft.com/de-de/library/dd321405(v=vs.110).aspx

ContinueWith() also can help you handle exceptions that occured while executing the task.

Upvotes: 0

Sriram Sakthivel
Sriram Sakthivel

Reputation: 73462

Almost there is no reason to directly deal with threads now. It is fairly easy to do with Task Parallel Library and async-await.

You start number of Tasks, keep the reference of tasks, and wait/await it when needed.

Task backupTask = Task.Run(() => BackupProcess(ServerName, SQLinstance, BackupPath, db_name));
Task someOtherTask = Task.Run(() => SomeOtherWork(anyParameter));
...
//Later at some point    
await Task.WhenAll(new []{backupTask, someOtherTask });
//At this point all tasks has been completed
//Do whatever you need to execute after all tasks finished

Note: BackupProcess can be made asynchronous if you use asynchronous API of your data provider without the use of Task.Run which makes a ThreadPool thread to wait there.

If you still wanted to go with Thread approach(which you shouldn't), you can use CountDownEvent for synchronization or Thread.Join on all the started threads.

Upvotes: 2

Related Questions