How to execute multiple tasks sequentially

Hi experts,

I am new to .net programming and I am having difficulty with one area.  I wrote (90% complete) a program which will allow me to quickly configure a hard drive once imaged.  The program opens up into a multi-tabbed form.  One of the tabs have fields for computer name, individual fields for putting in the IP, SNM, DGW etc.  I want my tech's to have the ability start the program, open the tab, fill out the appropriate fields then either apply all the settings with a single click of a button or just apply the settings for one of the separate sections ie: either computer name or IP Address only.  I am using visual Studios 2010.

Initially, I created sub routines for each task (change computer name, change IP address, etc).  I can execute each individual task (change computer name or change IP address) individually when i click the button to change the one section.   The issue is coding the config all button.  When this button is clicked, I want the program to start by executing the "change_computer_name" subroutine while all the other subroutines are waiting in queue.  Once the "change_computer_name"  subroutine is completed, the "change_IP_Add" subroutine launches.  

My research has lead me down the path of using a "BackgroundWorker" or using "Queuing" for this feature.  I have spent at least a full day (24 hours cumulative) exploring these possibilities however I cannot seem to get it done.  I pride myself on being able to self study and get it done but it’s time to swallow my pride and ask.

Any assistance would be appreciated.


Who is Participating?
Mike TomlinsonConnect With a Mentor Middle School Assistant TeacherCommented:
WaitForExit() will work but you need to use them in the right order:

    Dim P As Process = Process.Start("A.exe")
    P = Process.Start("B.exe")

In the above snippet, "B" will not start until "A" has completed.

If you run this code from a Button handler, though, then your main UI will freeze until all the processes complete.  This does make a difference if the processes are long as your application will experience a "white out" which is the inability to paint itself because the main UI thread is waiting for the processes to exit.  This is why you do need a different thread or a backgroundworker to spawn the processes and wait for them!
proceed on the path for one entry, where you call all routines for that entry.
On the ALL click, call the routines for each of the entries one after the other.

A backgroundworker would be used by me INSIDE each of the small routines: while the process of configuring something is going on, the techician may continue in the meantime on the desktop inserting date for the next operation. With the routine in foreground he has to wait until the ruotine has finished to continue his work. When the ALL part starts, I guess there is no more a need to keep the keyboard unlocked. He has to wait anyway until all has finished.
Jacques Bourgeois (James Burger)PresidentCommented:
The background worker is not the right thing to use, it will make all the jobs being executed in parallel, which is the contrary of what you want to do.

Queuing is the right thing, but you do not need to do it, it will be done automatically for you. .NET always terminate an event before going to the following one. So if the user press on 3 buttons in a row, the Click for the second button will be held back until the Click of the first one has executed. And then, the Click event of the third button will wait until the second Click has finished processing.

So, basically, you have nothing to do, it will be done for you.

You can check that by putting a MessageBox at the start and end of each of the Click events. You will see that they execute in sequence.
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

Mike TomlinsonMiddle School Assistant TeacherCommented:
...except that, without using a backgroundworker (or manual threads), the main UI will lock up and freeze while the tasks are being done.

Move the code out of each button and into their own methods; then make each button call its respective method.

Now, in your backgroundworker, you can just call each method sequentially.
Jacques Bourgeois (James Burger)PresidentCommented:
If the user has filled all the fields before clicking on the buttons, the main UI lock up won't be important. The clicks on the button will record anyway. A click just won't be processed until the previous one has finished.

If each button calls its respective method, "Now, in your backgroundworker, you can call each method sequentially" will be useless since the methods will have already been called on the click.

Since the jobs need to be done in sequence, using threads would completely break the requirement, since the role of threads is the opposite, processing in parallel. And in case of anything that has to do with the hard disk, threads are just a way to break performance, because the disk keeps having to move its heads continually because the system keeps switching between threads. Besides, that might well be the reason behind the need to process in sequence. It makes things faster.

I think that the best way to really execute in sequence without freezing the interface would be for the clicks to send a message to a queue and process the queue. That is more involved, and that is why I did not suggest it in the first place.

The way to go depends on the way you want the users to interact with the form.
israelantaAuthor Commented:
Ambusy, you are correct.  I didn't realize it because i wasn't trying to move or do anything else with my main UI but it does in face freeze.  I will have to do a background worker to stop that from happening.  Now back to the issue of how to create.  I will go back to Google and MSDN unless you have something pre done to throw this way.  I don't like asking but time is on my back.

JamesBurger: I tested the program and found out that what you said about .net queuing automatically is half true in the way i created the program.  for example: in the picture above  I created a sub routine for change computer name, change ip address, Microsoft loopback adapter and adding a comport number to the one mapping program we use. Each of these subs only go into the registry and do simple delete, add or change reg keys or in the case of the loopback adapter i am using wmi.  When i press the configure hard drive button, i call each of these subs in order ie:
In this button, the program does in fact wait for one to finish before starting another.

on the next tab of the program, I have a button to clean up the hard drive.  I want this button to execute a series of steps in order as well.  As before, I created a sub routine for each step.  the steps are as follows: delete recent items list, conduct a disk cleanup, clear event logs, defrag c:, defrag d, then show dialog box asking if I wan to shut down now or wait, if Yes is pressed, the computer shuts down.
The difference in these sub routines are that in these subs I am starting processes.  
Step 1 - delete recent Items: Reg key deletes and creates - this is fast and works fine.  program waits then goes on to next step.
Step 2- clear event logs:  this is a wmi script and works fine.  Program executes then goes on to next step.
Step 3-disk cleanup:  Here i am starting a process, this is where it starts running them at the same time.  It seems that when the process begins, VB is going on to the next step.  I also created a sub for this one:        System.Diagnostics.Process.Start("cleanmgr.exe", "/sagerun:1")

Step 4 and Step 5 are similar to above with the same results, when the process starts the program goes on.  
Step 4 is:  System.Diagnostics.Process.Start("defrag.exe", "c: -f")
Step 5 is:  System.Diagnostics.Process.Start("defrag.exe", "d: -f")
Step 6: Msg box works fine.
Note:  I even tried starting the process in the same button click routine using a .waitforexit .  I dimmed the process then called the process as follows:
dim diskcleanup as process = System.Diagnostics.Process.Start("cleanmgr.exe", "/sagerun:1")
and did the same for defrag C and D.
also tried "WaitForInputIdle".  these did not work as well.  This is the reason i think I need to add queuing.

Having rambled enough, if anyone agrees that I need to introduce queuing into the code to have these subs wait can you provide examples of queuing to launch subs or process sequentially.

Thanks again in advance.
israelantaAuthor Commented:
Idle Mind:

Do I do what you suggested in the subroutines I created or bring them back into the button_click event.  

right now I have a sub for each of those process, do I re-write the subs for each as indicated by  you above.  If I re-write the subs, then when I call them in the button_click event, do I use the WaitForExit ie: call cleanup.WaitForExit  or just call the sub normally  ie: call cleanup.  

Sorry in advance if this is a dumb question or if mixing up terminology, not school trained.
israelantaAuthor Commented:
Idle Mind:

Sorry, I misread your post.  I will try and post back with results
israelantaAuthor Commented:
Idle Mind:

Re-writing the process as indicated above worked for getting the tasks to run sequentially.  Now just waiting on some help from someone as to the background worker and how to implement in my senario.


1 of 2 down.
Mike TomlinsonMiddle School Assistant TeacherCommented:

Now for the good news and bad news.

Good News:  If you've already moved each subroutine into its own method then writing the "Config All" routine is simply a matter of calling each method from a single BackgroundWorker.

Bad News: Achieving "sequential" execution when the user manually clicks the different buttons is a bit trickier.  For that, as James mentioned, you'd need some kind of queuing system.  One way to do that would be to use a "master" BackgroundWorker() that pulls items from the queue and runs them.  As each button is clicked, that task would be added to the queue.

I'll post a simple queuing system later if no one else does.
Jacques Bourgeois (James Burger)PresidentCommented:
When you start a process, it starts on its own thread and your Click finishes, going to the following finish while the process is running in parallel. That is why System.Diagnostics.Process.Start("cleanmgr.exe", "/sagerun:1") does not work well in that scenario. That is also why I said from the start that working with threads or a Backgroundwork (that is only a simple way to work with threads) would not work.

I was not aware that you were calling external programs. In such case the best alternatives are the WaitForExit (easy to program but will freeze the application until all the jobs are finished) or a queue (a little more processing, but you get full control, such as the possibility to cancel between operations if desired).

Once again, I personnally do not think, the BackgroundWorker is not a good solution. You would need to have a queue anyway to accumulate the jobs, and as soon as you incorporate multithread in an application, you are bringing in synchronization issues. Starting a new thread (through Process.Start) inside of another one (the BackgroundWorker), inside of another one (your Form) could work on the first time if you are lucky, but you run the risk of falling into a very uninteresting debugging scenario. Not counting that there are special issues with threads and Process.Start. Give a look at the last paragraph before the examples of the Visual Studio 2010 documentation for Process.Start (string)

A simple Timer working with a queue would be, in my humble opinion, a lot safer as far as your own time is concerned.
israelantaAuthor Commented:
idle Mind

the good news is that in my program, while the potential is there for one of my techs to click the individual config buttons one at a time in rapid success, i doubt any of them will.  For that reason i think your solution for just creating the backgroundworker for the config all button would finish the program.  again, an example would be nice.


I am all for setting this program the best way, again, i am extremely new to this thus if you had a simple example i will try.  You menttion the Visual studio 2010 documentation, I will review once i find the section.  I will also review your last suggestion, again, an example would be nice.
Jacques Bourgeois (James Burger)PresidentCommented:
I am very busy today and tomorrow, I do not have the time to build and test an example. Will try to do that on Tuesday toward the end of the afternoon if I can find time.
israelantaAuthor Commented:

No problem, you have been great and I truely appreciate your advise.  I will continue to research your last suggestion.

Thanks again

Jacques Bourgeois (James Burger)Connect With a Mentor PresidentCommented:
Needed a small break, and your thing looks like a fun challenge.

Given a Form with 3 buttons to record the operations (Button1, Button2, Button3), and one button to launch the sequence (btnGo). Also a timer (Timer1) that is our main sequencing tool.

Adapt the following to your needs:
Public Class Form1

  Dim _operationQueue As New Collections.Generic.Queue(Of Button)
  Private Sub Buttons_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click, Button2.Click, Button3.Click

    Dim caller As Button = DirectCast(sender, Button)

    _operationQueue.Enqueue(caller)    'Add the button to the queue
    caller.Enabled = False            'If needed. Prevent the user from executing the same operation twice
    btnGo.Enabled = True              'Now that we have at least one operation, we can activate Go

  End Sub

  Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick

    If _operationQueue.Count > 0 Then

      Timer1.Enabled = False  'Prevents useless firing of the timer while we are processing one operation

      Dim app As Process
      Dim operation As Button = _operationQueue.Dequeue  'Get the next Button in the queue

      Select Case True
        Case operation Is Button1
          app = Process.Start("Calc.exe")
          app.WaitForExit()    'Freeze here. The timer being disabled, the following operations will wait
        Case operation Is Button2
          app = Process.Start("Notepad.exe")
        Case operation Is Button3
          app = Process.Start("C:\Program Files\Prog\Projects\JBBackup\bin\Debug\JBBackup.exe")
      End Select

      Timer1.Enabled = True  'Restart the timer, which will bring us back here and process the next operation.

    End If

  End Sub

  Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load

    Timer1.Enabled = False  'We do not want the time until we are ready to go
    btnGo.Enabled = False    'No need to click on Go until an operation has been selected

  End Sub

  Private Sub btnGo_Click(sender As Object, e As System.EventArgs) Handles btnGo.Click

    Timer1.Interval = 250      'A quarter of a second delay to leave time for an operation to start. Otherwise, 2 operations could launch in the same run. Increase if you se that this happens.
    Timer1.Enabled = True      'Start the timer

  End Sub

End Class

Open in new window

Feel free to ask if you need clarifications.

Hope this will suit your need.

israelantaAuthor Commented:
Sorry for the delay, i had to leave and work off site on a project.
israelantaAuthor Commented:
First of all I want to thank all of you who participated in providing solutions for this question.  I have been a member of Experts-Exchange since Jan 2006 and have always been impressed with the details provided in the solutions.  As my responsibility and workload increase, I find myself coming back to Experts-Exchange more and more.  While I have only asked 5 questions in the past 5 years, each solution was able to jump start a stalled project. As to this project, it is finished and in testing by some of my techs for proof of concept and completeness.  

As to the solutions, the original question was (How to execute multiple tasks sequentially).  Idel_Minds solution did the trick.  James, I could not get your code for creating and starting items in a queue to work but have not stopped trying.  I was pulled away for offsite support that consumed all of my time for the last few days.  Now that I am back I plan on working on the background worker or James queue to make the project complete.

Once again, thanks
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.