Click here to Skip to main content
14,970,229 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello,
I write a program that shall make an unattended SQL servers installation. There is a main form and many methods which I start in a top-down manner. It looks like that: collecting data and checking them, SQL servers install, install scripts, install service pack, install scripts etc. I would like to inform the user about the progress of the program (e.g. with progress bar). First I tried to work with BackgroundWorker, it works well but the Worker doesn’t wait (or should I say: I don’t know how to make it wait) for the previous method to be finished – what I actually need (there is no sense in installing Service Pack while the SQL Server is still not installed. I have found a proposal for solution of Jon Skeet site (http://www.yoda.arachsys.com/csharp/threads/winforms.shtml[^].). And used it in that way (here just one method: copy some data from drive A to drive B, after copying I should start SQL-Server installation, Service Pack etc.):

C#
private void button1_Click(object sender, EventArgs e)
        {
            SQLInstallation inst = new SQLInstallation();

            inst.LWCopy(ref myAl, "C:\\ABC", "C:\\BDC");

            pBar1.Visible = true;
            pBar1.Minimum = 0;
            pBar1.Maximum = myAl.Count;
            pBar1.Value = 1;
            pBar1.Step = 1;

            lock (stateLock)
            {
                target = myAl.Count;
            }
            Thread t = new Thread(new ThreadStart(ThreadJob));
            t.IsBackground = true;
            t.Start();
            
        }

        

        void ThreadJob()
        {
            Object[] jajco = myAl.ToArray();
            
            
            MethodInvoker updateCounterDelegate = new MethodInvoker(UpdateCount);
            int localTarget;
            lock (stateLock)
            {
                localTarget = target;
            }
            UpdateStatus("Installationsdateien kopieren.");
            lock (stateLock)
            {
                currentCount = 0;
            }
            Invoke(updateCounterDelegate);
            // Pause before starting
            Thread.Sleep(50);
            UpdateStatus("Counting");

            for (int i = 0; i < localTarget; i++)
            {
                lock (stateLock)
                {
                    string input = jajco[i].ToString().Substring(0, jajco[i].ToString().IndexOf(","));
                    string target = jajco[i].ToString().Substring(jajco[i].ToString().IndexOf(",") + 1);
                    File.Copy(input, target, true);
                    //pBar1.PerformStep();
                    currentCount = i;
                    strAnzeige = target;
                }
                // Synchronously show the counter
                Invoke(updateCounterDelegate);
                Thread.Sleep(50);
            }
            UpdateStatus("Finished");
            //Invoke(new MethodInvoker(EnableButton));
            myAl = null;
            jajco = null;

        }

        void UpdateStatus(string value)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new StringParameterDelegate(UpdateStatus), new object[] { value });
                return;
            }
            // Must be on the UI thread if we've got this far
            lblStatus.Text = value;
        }

        void UpdateCount()
        {
            int tmpCount;
            lock (stateLock)
            {
                tmpCount = currentCount;
            }
            pBar1.Value = tmpCount;
            lblStatus.Text = "Coping..: " + strAnzeige;
        }



Is this the solution or shall try to solve the problem writing a queue?
A help would be appreciate...
Thanks
Andy
Posted
Updated 8-May-11 22:58pm
v2
Comments
Richard MacCutchan 9-May-11 4:26am
   
Please format your code properly with <pre> tags.

I think you miss the point in using threads. Threads are used to execute code in parallel (more or less). You are trying to synchronize the threads again, which raises the question why you use threads at all. If you succeed in synchronizing them the way you want, then it will be as if you did not use threads at all. So why put time and effort into setting up threads at all?

Edit: The threads will of course help to keep the user interface responsive, so you may want to keep them. But why don't you simply make sure in your form that the buttons to start the threads are enabled in sequence. Or start the threads one after another without any buttons. The form can check the status of the currently running thread with the IsAlive property.
   
v2
Hello,
thank you for your answer. It's correct: multithreads are quite new to me...
It can be that I should use something completely different. So how shall I solve my problem?
1. there is a main form and a button starting many methods top-down
2. The problem, of course, is that my application is single-threaded, so while the thread is doing something (copying files, installing SQL Server etc.), it can't also be drawing the UI.
But I will to inform the user what's going on, the main form is "frozen" and it looks like the program were crashed. Therefore the idea with several thread.
Andy
   
Comments
[no name] 9-May-11 5:31am
   
Look above. The threads will keep the form responsive, so they are of use after all. Your form just should start them in sequence, not all at once. You could add a timer to the form which checks once every second if the current thread is finished (with the IsAlive property of the thread). If the thread is finished, then it starts the next one.
hm, putting the things together is the big problem for me.
How to start the threads in sequence?
Let's say I tray it in that way:

<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Threading
{
public class Worker
{
// This method will be called when the thread is started.
public void DoWork1()
{
while (!_shouldStop)
{
Console.WriteLine("worker1 thread: working...");
}
Console.WriteLine("worker1 thread: terminating gracefully.");
}

public void DoWork2()
{
while (!_shouldStop)
{
Console.WriteLine("worker2 thread: working...");
}
Console.WriteLine("worker2 thread: terminating gracefully.");
}

public void DoWork3()
{
while (!_shouldStop)
{
Console.WriteLine("worker3 thread: working...");
}
Console.WriteLine("worker3 thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
static void Main()
{
Worker workerObject = new Worker();
RunThread(new Thread(workerObject.DoWork1));
RunThread(new Thread(workerObject.DoWork2));
RunThread(new Thread(workerObject.DoWork3));
}

public static void RunThread(Thread ThreadInstance)
{
if(ThreadInstance != null)
{
ThreadInstance.Start();
while(!ThreadInstance.IsAlive);
Thread.Sleep(1000);
workerObject.RequestStop();
ThreadInstance.Join();
}
}
}
}
</pre>

But it's not correct, what I get is:
worker1 thread: working...
worker1 thread: working...
main thread: Starting worker thread...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: terminating gracefully.
worker1 thread: working...
worker1 thread: working...
worker1 thread: terminating gracefully.
worker2 thread: working...
worker2 thread: working...
worker2 thread: working...
worker2 thread: terminating gracefully.
main thread: Worker thread has terminated.

what means, that the sequence run wrong: first a chunk of thread1, than 3 completly, then a chunk of 1, then 2. What I wanted was: thread 1, 2, 3.
Could you help me?
   
v3
Comments
[no name] 9-May-11 7:48am
   
Please stop posting answers to your own question.

And you did it again: In the Main() method you started all threads at once again. Look at how I modified it. This should work better (barring any typos). Nonetheless, this is not really good as it is. For one thing, the threads run in endless loops and must be stopped. They should execute their task and stop when finished by themselves. This whole wait-for-start-sleep-a-bit-stop-the-thread-and-wait-for-it-to-die stuff is good only for demonstration.
andywawa 9-May-11 8:01am
   
ups, sorry for posting the answers..
thank you for the answer. Ok, I can see what you mean. I'm fully aware that my solution with the different threads is a bit cumbersome, but I still don't know the proper approach to solve my problem? Simply put: I need an idea how a professional programmer (not a new-be just like me) would do it?
Andy
[no name] 9-May-11 8:28am
   
Sorry, but I'm at work right now and can't do it right now. Try this.

1) Add a new WinForm

2) Add a Timer to the form. Set Enabled to false and the time to 500 milliseconds

3) Add an int as member to the form and initialize it with 0 in the constructor

4) Add a Thread as member to the form and initialize it with null in the constructor

5) Add a button to the form

6) Add a click event to the button. In the event handler you must enable the timer (Enabled = true) to start.

7) Add a timer event when the time is up (just double click the timer).

8) In the timer event you start a new Thread whenever the Thread member (Step 4) is null or when Thread.IsAlive == false. The int from step 3 will tell you which Thread must be started. Increment the int after starting the thread. In case you are through with all steps, don't start a new thread and disable the timer again and set the int back to 0 and the Thread member to null.


This does not report any progress and also does not stop the threads. You can add that later. Also, it counts on the threads finishing some time and not run in endless loops. For testing, let them count to a high number, but not endlessly.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900