Solved

Create child process in C#

Posted on 2014-10-14
8
1,758 Views
Last Modified: 2014-10-15
Hi Experts,

Lets me describe. Currently what we have is that an C# application console that run bat files sequential. The console app just creates a process to run a bat file. It waits for the bat file executes until complete and then runs the other ones. Please notice that all the bat file with same name 1.bat

Here is the code:
 foreach(string clientDirectory in clientDirectories)
                    {
                        System.IO.Directory.SetCurrentDirectory(clientDirectory);
                        if (System.IO.File.Exists(System.IO.Path.Combine(clientDirectory, "1.bat")))
                        {
                            ExecuteCommand(System.IO.Path.Combine(clientDirectory, "1.bat"));
                        }
                    }


static void ExecuteCommand(string command)
        {
            int exitCode;
            ProcessStartInfo processInfo;
            Process process;

            processInfo = new ProcessStartInfo("cmd.exe", "/c \"" + command + "\"");
            processInfo.CreateNoWindow = true;
            processInfo.UseShellExecute = false;
            // *** Redirect the output ***
            processInfo.RedirectStandardError = true;
            processInfo.RedirectStandardOutput = true;

            process = Process.Start(processInfo);
            process.WaitForExit();

            // *** Read the streams ***
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            exitCode = process.ExitCode;

            Console.WriteLine(System.IO.Directory.GetCurrentDirectory());
            Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
            Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
            Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
            process.Close();
        }

Open in new window


Now I want to change from running bat files sequentially to parallel. What I think is that the console C# app creates multiple parallel processes. Once child process finishes his task, he closes himself or notifies parent process. It should be great if console app could check current machine has enough memory available or not before creating new process (Let say allocate static 200MB for each).

I am actually research on that but it would shorten my time if experts put some thoughts here.

Thanks in advance,
Dave
0
Comment
Question by:David_Duong
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
8 Comments
 
LVL 40

Expert Comment

by:Kyle Abrahams
ID: 40381023
The below should work for executing different threads.   As for checking the different memory I'm not sure about.


using System.Threading;

{
List<thread> threads = new List<threads>();
foreach(string clientDirectory in clientDirectories)
                    {
                       Thread t = new Thread(new ThreadStart(processDIr));
                       t.Start(clientDirectory);
                        threads.add(t);
                    }

//wait until all threads no in background or running state.  You may need to add others.
while (threads.Where(r => r.ThreadState == ThreadState.Background || r.ThreadState == ThreadState.Running).Count() > 0)
   Thread.Sleep(1000);

}

private void processDIr(object Dir)
{  
   string clientDirectory = Dir.ToString();

                        System.IO.Directory.SetCurrentDirectory(clientDirectory);
                        if (System.IO.File.Exists(System.IO.Path.Combine(clientDirectory, "1.bat")))
                        {
                            ExecuteCommand(System.IO.Path.Combine(clientDirectory, "1.bat"));
                        }
}

//ExecuteCommand remains untouched.

Open in new window

0
 
LVL 34

Expert Comment

by:it_saige
ID: 40381083
As opposed to using a Thread.Sleep(x); I would recommend using Events to signal with the Thread has completed; e.g. -
using System;
using System.Collections.Generic;
using System.Threading;

namespace CSharpThreadExampleExample
{
	public class Worker
	{
		#region ThreadWorderCompleted Memebers
		[NonSerialized]
		private ThreadWorkerCompletedEventHandler _threadWorkerCompleted;
		public event ThreadWorkerCompletedEventHandler ThreadWorkerCompleted
		{
			add { _threadWorkerCompleted += value; }
			remove { _threadWorkerCompleted -= value; }
		}

		protected virtual void OnThreadWorkerCompleted(object sender, ThreadWorkerCompletedEventArgs e)
		{
			ThreadWorkerCompletedEventHandler handler = _threadWorkerCompleted;
			if (handler != null)
				handler(sender, e);
		}
		#endregion

		private bool shouldStop = false;
		private int id = -1;
		public int ID
		{
			get { return id; }
			private set 
			{ 
				if (!value.Equals(id))
					id = value;
			}
		}

		public void DoWork()
		{
			int count = 0;
			while (!shouldStop)
			{
				Console.WriteLine(string.Format("Worker Thread {0}: Working ({1} passes)...", ID, count + 1));
				// Simulating long running process.
				Thread.Sleep(200);
				count++;
				if (count == 5)
					shouldStop = true;
			}
			Console.WriteLine(string.Format("Worker Thread {0}: Terminating gracefully", ID));
			OnThreadWorkerCompleted(this, new ThreadWorkerCompletedEventArgs(ID));
		}

		public void RequestStop()
		{
			shouldStop = true;
		}

		private Worker() { ;}

		public Worker(int ID)
		{
			id = ID;
		}
	}

	class Program
	{
		static AutoResetEvent reset = new AutoResetEvent(false);
		static List<Worker> workers = new List<Worker>();
		static bool creatingThreads = false;

		static void Main(string[] args)
		{
			creatingThreads = true;
			for (int i = 0; i < 5; i++)
				CreateAndStartThreads(i + 1);
			Console.WriteLine("Settings the reset event to block the main thread");
			reset.WaitOne();
			Console.WriteLine("Finished executing all threads.");
			Console.ReadLine();
		}

		public static void CreateAndStartThreads(int ID)
		{
			Worker worker = new Worker(ID);
			worker.ThreadWorkerCompleted += OnThreadWorkerCompleted;
			Thread thread = new Thread(worker.DoWork) { Priority = ThreadPriority.Normal, IsBackground = true };
			thread.Start();
			Console.WriteLine(string.Format("Adding worker with ID - {0}", ID));
			workers.Add(worker);

			if (ID == 5)
				creatingThreads = false;
		}

		public static void OnThreadWorkerCompleted(object sender, ThreadWorkerCompletedEventArgs e)
		{
			if (sender is Worker)
			{
				Console.WriteLine(string.Format("Removing worker with ID - {0}", (sender as Worker).ID));
				workers.Remove(sender as Worker);
				if (!creatingThreads && workers.Count == 0)
					reset.Set();
			}
		}
	}

	public delegate void ThreadWorkerCompletedEventHandler(object sender, ThreadWorkerCompletedEventArgs e);

	public class ThreadWorkerCompletedEventArgs : EventArgs
	{
		// Ideally you really want to use items that can identify the thread.
		public int ID { get; private set; }

		private ThreadWorkerCompletedEventArgs()
		{
			ID = default(int);
		}

		public ThreadWorkerCompletedEventArgs(int ID)
		{
			this.ID = ID;
		}
	}
}

Open in new window

I would also say look into using a QueueUserWorkItem (part of the ThreadPool class) as opposed to a standard thread model.  This is because being a part of a thread pool, the QueueUserWorkItem waits until a thread in the thread pool becomes available before consuming it.  This would allow for you to allocate resources and such depended upon your thread pool configuration.

http://msdn.microsoft.com/en-us/library/system.threading.threadpool.queueuserworkitem(v=vs.110).aspx

-saige-
0
 
LVL 34

Expert Comment

by:it_saige
ID: 40381107
Here is the above example, modified to use a QueueUserWorkItem:
using System;
using System.Collections.Generic;
using System.Threading;

namespace QueueUserWorkItemExample
{
	public class QueueWorker
	{
		#region QueueWorderCompleted Memebers
		[NonSerialized]
		private QueueWorkerCompletedEventHandler _queueWorkerCompleted;
		public event QueueWorkerCompletedEventHandler QueueWorkerCompleted
		{
			add { _queueWorkerCompleted += value; }
			remove { _queueWorkerCompleted -= value; }
		}

		protected virtual void OnQueueWorkerCompleted(object sender, QueueWorkerCompletedEventArgs e)
		{
			QueueWorkerCompletedEventHandler handler = _queueWorkerCompleted;
			if (handler != null)
				handler(sender, e);
		}
		#endregion

		private bool shouldStop = false;
		private int id = -1;
		public int ID
		{
			get { return id; }
			private set
			{
				if (!value.Equals(id))
					id = value;
			}
		}

		public void DoWork()
		{
			int count = 0;
			while (!shouldStop)
			{
				Console.WriteLine(string.Format("Queue Worker Thread {0}: Working ({1} passes)...", ID, count + 1));
				// Simulating long running process.
				Thread.Sleep(200);
				count++;
				if (count == 5)
					RequestStop();
			}
			Console.WriteLine(string.Format("Queue Worker Thread {0}: Terminating gracefully", ID));
			OnQueueWorkerCompleted(this, new QueueWorkerCompletedEventArgs(ID));
		}

		public void RequestStop()
		{
			shouldStop = true;
		}

		private QueueWorker() { ;}

		public QueueWorker(int ID)
		{
			id = ID;
		}
	}

	class Program
	{
		static AutoResetEvent reset = new AutoResetEvent(false);
		static List<QueueWorker> workers = new List<QueueWorker>();
		static bool creatingThreads = false;

		static void Main(string[] args)
		{
			creatingThreads = true;
			for (int i = 0; i < 5; i++)
				CreateAndStartThreads(i + 1);
			Console.WriteLine("Settings the reset event to block the main thread");
			reset.WaitOne();
			Console.WriteLine("Finished executing all queued worker threads.");
			Console.ReadLine();
		}

		public static void CreateAndStartThreads(int ID)
		{
			QueueWorker worker = new QueueWorker(ID);
			worker.QueueWorkerCompleted += OnQueueWorkerCompleted;
			ThreadPool.QueueUserWorkItem(state => worker.DoWork());
			Console.WriteLine(string.Format("Adding queue worker thread with ID - {0}", ID));
			workers.Add(worker);

			if (ID == 5)
				creatingThreads = false;
		}

		public static void OnQueueWorkerCompleted(object sender, QueueWorkerCompletedEventArgs e)
		{
			if (sender is QueueWorker)
			{
				Console.WriteLine(string.Format("Removing queue worker thread with ID - {0}", (sender as QueueWorker).ID));
				(sender as QueueWorker).QueueWorkerCompleted -= OnQueueWorkerCompleted;
				workers.Remove(sender as QueueWorker);
				if (!creatingThreads && workers.Count == 0)
					reset.Set();
			}
		}
	}

	public delegate void QueueWorkerCompletedEventHandler(object sender, QueueWorkerCompletedEventArgs e);

	public class QueueWorkerCompletedEventArgs : EventArgs
	{
		// Ideally you really want to use items that can identify the thread.
		public int ID { get; private set; }

		private QueueWorkerCompletedEventArgs()
		{
			ID = default(int);
		}

		public QueueWorkerCompletedEventArgs(int ID)
		{
			this.ID = ID;
		}
	}
}

Open in new window


-saige-
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:David_Duong
ID: 40381175
Hi Guys, I appreciate your quick and great comment. I should research on muti-thread programming instead of multiple processes. Kind of navie question title :)

Anyway, I actually see that .NET 4 has Task Parrallel Library (TPL). I produced some code to test and actually it shorten the copy time.
class Program
    {
        static void Main(string[] args)
        {
            string fromFolder = @"C:\Users\hduong\Downloads";
            string toSequentialFolder = @"C:\Encompass2Arg-Seq";
            string toParallelFolder = @"C:\Encompass2Arg-Pal";
            
            Stopwatch stopwatch = new Stopwatch();

            Console.WriteLine("Executing sequential copy...");
            stopwatch.Start();
            copyFileSequently(fromFolder, toSequentialFolder);
            stopwatch.Stop();
            Console.WriteLine("Sequential loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);

            stopwatch.Reset();
            Console.WriteLine("Executing parallel copy...");
            stopwatch.Start();
            copyFileParallel(fromFolder, toParallelFolder);
            stopwatch.Stop();
            Console.WriteLine("Parallel loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);



        }

        static void copyFileSequently(string fromFolder, string toFolder)
        {
            string[] files = Directory.GetFiles(fromFolder);
            foreach (string currentFile in files)
            {
                //Console.WriteLine(currentFile + "\n");
                File.Copy(currentFile, Path.Combine(toFolder, Path.GetFileName(currentFile)), true);
            }
        }

        static void copyFileParallel(string fromFolder, string toFolder)
        {
            string[] files = System.IO.Directory.GetFiles(fromFolder);
            Parallel.ForEach(files, currentFile =>
                {
                    File.Copy(currentFile, Path.Combine(toFolder, Path.GetFileName(currentFile)), true);
                }
                );
        }

Open in new window


Do you guys think that TPL would help in my multiple bat program by creating mutiple tasks?
0
 
LVL 34

Accepted Solution

by:
it_saige earned 300 total points
ID: 40381217
If you are using .NET 4, I would say definately.  

-saige-
0
 
LVL 40

Assisted Solution

by:Kyle Abrahams
Kyle Abrahams earned 200 total points
ID: 40382308
Given the application is used for file copying I would actually advise caution here.  This is one of those answers where it depends.

If you're copying multiple files from the same source and destination you could actually be creating more seeks on the hard drives as the OS tries to accomplish everything at once.  You'll of course have more power if they're all different sources and destinations (and when I say that I mean different hard drives, not directories or even partitions).  

Is the list of files deterministic in that it's executing pretty much the same files every day?  

If you have a few files for the same source / destination it might be better to group them by source / destination and then do those in a serial fashion.  

Just some considerations before a carte blanch yes can be given.
0
 

Author Comment

by:David_Duong
ID: 40382615
Kyle,

The list of files is pre-defined and pretty much the same everyday.

I already commit my code that use TPL.  
Thanks both of you,
0
 

Author Closing Comment

by:David_Duong
ID: 40382625
Really helpful comments with excellent code.
0

Featured Post

How Do You Stack Up Against Your Peers?

With today’s modern enterprise so dependent on digital infrastructures, the impact of major incidents has increased dramatically. Grab the report now to gain insight into how your organization ranks against your peers and learn best-in-class strategies to resolve incidents.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
aspx ascx, c# 7 45
vb.net application has warrnings about VB6 calls. 2 48
SQL Server Serialization error 8 49
How to input barcode scanner data into textbox in C#  ? 13 73
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

710 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question