I have to run 3 processes sequentially, one after other. The second process must start after first process' completion.
I work in C#. I have used Process.Start() method, Where it kicks on all at same time.
Can anyone help me.
One way of doing it adding a handler for the Exited event of the first process, and then starting the second process from there.
void StartProcessOne() {
Process p = Process.Start("foo", "bar");
p.Exited += (sender, e) => StartProcessTwo();
p.Start();
}
void StartProcessTwo() {
Process p = Process.Start("foo2", "bar2");
p.Exited += (sender, e) => StartProcessThree();
p.Start();
}
...
You can also use the WaitForExit() method, which waits for the process to end before continuing execution of your code. Note, however, this makes your own process stop execution until the other process terminates. This can leave you with an unresponsive user interface and such, which can be quite undesirable.(source)
Process.Start("yourprogram.exe").WaitForExit();
Process.Start("yournextprogram.exe").WaitForExit();
and so on...
You can accomplish this by responding to the Process.Exited event.
You should use this approach instead of WaitForExit() because the latter will block your program from responding to user input, etc...
private int n = 0;
private void StartAProcess()
{
Process process = new Process {
StartInfo = {FileName = "cmd.exe", Arguments = "pause"},
EnableRaisingEvents = true};
process.Exited += process_Exited;
process.Start();
n++;
}
void process_Exited(object sender, EventArgs e)
{
if (n < 3) StartAProcess();
}
try this code for each process
Process.WaitForExit()
http://msdn.microsoft.com/en-us/library/aa326953(v=VS.71).aspx
If you are using .NET 4 you could use the System.Threading.Tasks API. If your graph gets more complex you may get some mileage from http://pdag.codeplex.com (I must confess, this is my work).
You need to do a process.join() to wait for the first process to complete before submitting the next one. However, the bigger question is why you are using Process.Start() - for asynchronous tasks - when you actually want them to run synchronously? Just calling:
a();
b();
c();
will run them one after another.
Related
I have a dataGridView where I run a Process for each entry
and then update a toolStripProgressBar based on the output from the Process.
I have looked at the following threads,
Run two async tasks in parallel and collect results in .NET 4.5
Progress bar in parallel loop invocation
how to update the progress bar from tasks running concurrently
but I am not sure how to change my current code to something along these lines.
The main difference from these threads, as I see it, is that my computations are done by an outside application,
which I then need to collect the output from.
I guess I have to define each Process as an async task and then somehow collect the output.
For simplicity the processes are equal weighted in the sample code.
private iNumProcesses;
private void RunApps()
{
iNumProcesses = dataGridView1.Rows.Count;
string sPath = .exe application path
for (int i = 0; i < iNumProcesses; i++)
{
string sArgs = dataGridView1.Rows[i]["Arguments"].ToString();
ExecuteProgram(sPath, sArgs);
}
}
private void ExecuteProgram(string sProcessName, string sArgs)
{
using (cmd = new Process())
{
cmd.StartInfo.FileName = sProcessName;
cmd.StartInfo.Arguments = sArgs;
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.ErrorDialog = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmd.ErrorDataReceived += new DataReceivedEventHandler(SortOutputHandler);
cmd.Start();
cmd.BeginOutputReadLine();
while (!cmd.HasExited) { Application.DoEvents(); }
}
}
private void SortOutputHandler(object sender, DataReceivedEventArgs e)
{
Trace.WriteLine(e.Data);
this.BeginInvoke(new MethodInvoker(() =>
{
if (e.Data == "Start") { do something... }
else if (e.Data == "Finish") { do something... }
else if (e.Data == "End") { do something... }
else
{
// .exe application output numbers 1 through 100
toolStripProgressBar1.Value += Math.Round(Convert.ToInt32(e.Data)/iNumProcesses,0);
}
}));
}
How can I run the processes in parallel and update the progress bar
based on the output numbers 1 through 100 I get from the .exe applications?
Any advice or suggestions will be greatly appreciated.
My answer to this question is not particularly associated with "C#" and therefore I'm not going to speak directly in those terms: this unexpectedly-thorny issue is actually universal.
The first thing that you must do is to arrange to periodically update the user display. To avoid nasty race-conditions and other problems, you should have "the main thread" perform this task, driven by a millisecond timer. The thread consults a shared array of progress-information and updates all of the progress-bars accordingly. (If you want to use an event to avoid outright "timed waiting," feel free to do so.)
Since each of the launched child processes will have their own input and output streams, and will be writing to those streams asynchronously, you will find it necessary to spawn a "mommy thread" within your application to supervise each child. This thread corresponds to a particular external process, and, in fact, is the one that launches it. The thread continues to exist until it determines that the process that it launched has died.
The "mommy thread" observes the output-stream(s) of its appointed ward to determine its "progress." It updates the progress-variables in the shared array accordingly. (A key element of this design is that each "mommy thread" is able to pay 100% of its attention to just its child. And, because all the "mommies" are threads, they can easily share information with the thread that's updating those progress bars.)
Do you actually have to use semaphores-and-such to coordinate access between the mommy-threads and the main? Depending of course upon the exact internal implementation of that data-structure, the answer just might be, "probably not." (Oh, but it's probably safest to do it anyway.)
In C#, I can start a process with
process.start(program.exe);
How do I tell if the program is still running, or if it closed?
MSDN System.Diagnostics.Process
If you want to know right now, you can check the HasExited property.
var isRunning = !process.HasExited;
If it's a quick process, just wait for it.
process.WaitForExit();
If you're starting one up in the background, subscribe to the Exited event after setting EnableRaisingEvents to true.
process.EnableRaisingEvents = true;
process.Exited += (sender, e) => { /* do whatever */ };
Process p = new Process();
p.Exited += new EventHandler(p_Exited);
p.StartInfo.FileName = #"path to file";
p.EnableRaisingEvents = true;
p.Start();
void p_Exited(object sender, EventArgs e)
{
MessageBox.Show("Process exited");
}
Be sure you save the Process object if you use the static Process.Start() call (or create an instance with new), and then either check the HasExited property, or subscribe to the Exited event, depending on your needs.
Assign an event handler to the Exited event.
There is sample code in that MSDN link - I won't repeat it here.
Take a look at the MSDN documentation for the Process class.
In particular there is an event (Exited) you can listen to.
Is there a way to run a bit of code when the current process is getting terminated?
I want to log some stuff when a process terminates (either through external means - eg killing it - or quitting in the application itself).
We're talking about a Console application written in c#.
Thanks!
Have a look here: atexit, exit delegate in c#
I am not sure, but something similar would help
Process process = new Process();
.
.
process.Exited += new EventHandler(myProcess_Exited);
process.Start();
private void myProcess_Exited(object sender, System.EventArgs e)
{
eventHandled = true;
customAction(); // your logging stuff here
}
public void customAction()
{
//
}
have a look at: Process.Exited Event
Not exactly sure on the terminology here but here I go basically I have the main() thread of my application that starts and calls two threads, one sets up an event handler to wait for specific registry keys to change, while the other starts a timer to write any changes made to an xml file every 5 mins or so and runs continuously. The issue I have is that once the two methods called are initialized it goes back to main and ends the program. My relevant code sections can be found below, so any help would be appreciated:
static void Main(string[] args)
{
runner one = new runner();
runner two = new runner();
Thread thread1 = new Thread(new ThreadStart(one.TimerMeth));
Thread thread2 = new Thread(new ThreadStart(two.start));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
}
public void TimerMeth()
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 300000;
timer.Enabled = true;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
file write = new file();
write.write(RegKeys);
}
public void start()
{
if (File.Exists("C:\\test.xml"))
{
file load = new file();
RegKeys = load.read(RegKeys);
}
string hiveid = "HKEY_USERS";
WindowsIdentity identity = WindowsIdentity.GetCurrent();
string id = identity.User.ToString();
string key1 = id + "\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Windows Messaging Subsystem\\\\Profiles\\\\Outlook\\\\0a0d020000000000c000000000000046";
List<string> value1 = new List<String> { "01020402", "test" };
valuechange = new RegistryValueChange(hiveid, key1, value1);
valuechange.RegistryValueChanged += new EventHandler<RegistryValueChangedEventArgs>(valuechange_RegistryValueChanged);
try
{
valuechange.Start();
}
catch
{
StreamWriter ut;
ut = File.AppendText("C:\\test.txt");
ut.WriteLine("error occured in starting management");
ut.Close();
}
file test = new file();
test.checkfile("C:\\test.xml");
}
void valuechange_RegistryValueChanged(object sender, RegistryValueChangedEventArgs e)
{
// deals with the returned values
}
Basically all the code works fine I've been testing it in a windows form application but now I need to run it in a standalone app with no interface in the background and need it to keep writing to the xml file and the change event to stay alive.
As you can expect, the Main() method is terminating because execution flows out of the Join() methods back to the main thread, and then terminates.
Either place loops in the methods TimerMeth() and start(), or more appropriately redesign the application into a Windows Service (as zac says).
You have a couple of issues.
Your first thread is simply creating a timer (which launches another thread). This thread is terminating very quickly, making your call to Join rather meaningless. What this thread should be doing is actually doing the waiting and the checking. You can easily adapt your code like this:
public void TimerMeth()
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 300000;
timer.Enabled = true;
try
{
while(true)
{
OnElapsedTime(null, null); // you should change the signature
Thread.Sleep(30000);
}
}
catch(ThreadAbortException)
{
OnElapsedTime(null, null);
throw;
}
}
Obviously you should change the signature of OnElapsedTime to eliminate the parameters, since they aren't used here.
I have a feeling that something is amiss in the way that the file handling is being done, but given that I don't understand exactly what that code does, I'm going to refrain from commenting. What, exactly, is the purpose of the file? Where is RegKeys defined?
Try building this into a windows service.
This thread contains two suggestions for finding the logged on user from a windows service, but I am not sure if they work.
Your methods will run once, then the thread will exit. There is nothing to keep them running.
Try this:
thread1.IsBackground = true;
thread2.IsBackground = true;
public void start()
{
while(true)
{
// ... do stuff
Thread.Sleep(1000*60*5) // sleep for 5 minutes
}
}
public void TimerMeth()
{
while(true)
{
file write = new file();
write.write(RegKeys);
Thread.Sleep(30000);
}
}
As other posters have noted, you will also then need to ensure your main method doesn't exit. Making the application a windows service seems like a good way to solve this in your case.
You might also want to handle ThreadInterruptedException and ThreadAbortException on your threads.
And if you really want to get into the nitty gritty of threading, check out this Free C# Threading E-Book by Joe Albahari.
To keep the main thread alive, one of the simplest ways is to add the following line to the end of your main function:
Thread.Sleep(Timeout.Infinite);
The Thread will terminate when your ThreadStart function returns, which allows the main thread to continue after Join(). Since you are just setting up a timer to fire off, the method will return very quickly. You need to provide a lock of some sort to keep your application from exiting.
Also, it doesn't look like you need to use threads at all to do what you are trying. Instead, just use the Timer and provide the lock to keep your Main() from terminating.
It looks to me like all of your functions are completing? ie, they all "fall out the bottom". Once all the functions have run through there is nothing left to do and your app will close. You want to run a loop of some sort in main.
You will also need to take a look at your timer. I suspect it is currently being garbage collected. You create it in the scope of your function but that function is being left so there is no longer a reference to your timer and it will be collected. Your timer needs to be a root.
I have a process, i can start, and hide working fine, but i want to read from the console program, when i runs, not after, i tried to run a timer, anbd read at the tick, but my program just crashes and when it not do, i get nothing at all.
startInfo= new ProcessStartInfo("cmd.exe");
startInfo.Arguments ="/C uus.exe "+ arg.ToString();
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
this.timer1.Enabled=true;
this.listBox1.Items.Clear();
p= Process.Start(startInfo);
Application.DoEvents();
void Timer1Tick(object sender, EventArgs e)
{
string str="";
str=p.StandardOutput.ReadLine();
if(str != null)
{
this.Text=str.ToString();
this.listBox1.Items.Add(str);
}
Application.DoEvents();
}
So what do i do to solve this?
Update:
I tried bender suggestion
now My program don't crash anymore, but also don't recvie any data
proc.StartInfo.UseShellExecute=false;
proc.StartInfo.CreateNoWindow=true;
proc.StartInfo.RedirectStandardOutput=true;
proc.StartInfo.RedirectStandardError=true;
proc.StartInfo.FileName="uus.exe";
proc.StartInfo.Arguments=arg;
proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(SortOutputHandler);
proc.Start();
proc.BeginOutputReadLine();
void SortOutputHandler(object o,System.Diagnostics.DataReceivedEventArgs e)
{
string str="";
string str2="";
str=e.Data.ToString();
if(str!=null && str!="")
{
this.listBox1.Items.Add(str.ToString());
this.Text=str.ToString();
}
str2=proc.StandardOutput.ReadLine();
if(str2!=null && str2!="")
{
this.lsw1.Items.Add(str2.ToString());
}
}
hmm?
Update:
I have changed the handler, because i have being tell, it can't do it, that it wil be cross thread operation, usualyy i wille have get an error if it was.
private delegate void TextAdderDelegate(string str);
void TextAdder(string str)
{
if(this.lsw1.InvokeRequired==true)
{
Invoke(new TextAdderDelegate(TextAdder),new object[] {str});
}
else
{
this.lsw1.Items.Add(str);
}
}
void SortOutputHandler(object o,System.Diagnostics.DataReceivedEventArgs e)
{
string str="";
if(e!=null)
{
if(e.Data!=null)
{
str=e.Data.ToString();
}
}
TextAdder(str);
}
The problem is that you're running on one thread and trying to write using another. When you created your background thread using the Timer's tick event, it can't have frontend user input.
Perhaps if you explained the big picture of what you're trying to accomplish, we can better help you.
In the meantime, you might want to create threadsafe writes. This article will help you to understand the problem and solution to writing to form controls on different threads.
You may create the Process instance explicitly (e.g. new Process)and use the OutputDataReceived event, the method BeginOutputReadLine() and, when finished CancelOutputRead() for that.
The event OutputDataReceived will be repeatedly called asynchronously from a different thread as soon output data is available.
I assume you get an 'thread cross exception', this may be caused because you're updating your form controls on an other thread then the UI thread.