1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
| using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
namespace MapnikWrapperTester
{
/// <summary>
/// process pool Class
/// </summary>
public class Pool_process
{
// Size of the pool, defines how many processes will be started
private const int POOL_SIZE = 5;
// singelton
private static Pool_process _unique;
// list of instanciated process
private List<Couple> processList;
// number to iterate images
private uint _tileNum;
// tell if the class is being disposed
private bool _isDisposing;
// constructor
private Pool_process()
{
processList = new List<Couple>();
for (int i = 0; i < POOL_SIZE; i++)
{
// loads as many process as needed
processList.Add(new Couple(newProcess(true)));
}
_tileNum = 0;
_isDisposing = false;
}
/// <summary>
/// pick a free process and execute the command
/// </summary>
/// <param name="args">command aruments</param>
/// <returns>result of process</returns>
public Image execute(string args)
{
Couple cp = getFreeProc(); // try to pick a process from the pool
Image img;
// image path
string map_res_path = @"C:\temp\map_out\map" + _tileNum++ + ".png";
// get a free proc
if (cp != null)
{
Process proc = cp.Proc;
cp.AutoEvent = new AutoResetEvent(false);
proc.StandardInput.WriteLine(args + " -O \"" + map_res_path + "\" go");
// wait for the map has been done (see Pool_Process.on_proc_output(...) )
cp.AutoEvent.WaitOne();
proc.StandardInput.WriteLine("1"); // don't stop the process;
}
else // if no free Process available, creates a new one
{
Console.WriteLine("Pool is fully used, creating a new process");
Process proc = newProcess(false);
proc.StandardInput.WriteLine(args + " -O \"" + map_res_path + "\" go 0"); // add "0" to tell the process to exit
proc.WaitForExit();
proc.Close();
}
// map is done
img = Image.FromFile(map_res_path);
return img;
}
// get a free process in the list. returns null if all processes in use
[MethodImpl(MethodImplOptions.Synchronized)]
private Couple getFreeProc()
{
for(int i=0 ; i<processList.Count ; i++)
if (processList[i].IsUsed == false)
{
processList[i].IsUsed = true;
return processList[i];
}
return null;
}
/// <summary>
/// get unique instance of the Class
/// </summary>
/// <returns>Pool_process</returns>
public static Pool_process getInstance()
{
if (_unique == null)
_unique = new Pool_process();
return _unique;
}
// triggered when process in pool is exiting
private void on_proc_Exit(Object sender, EventArgs e)
{
if (sender is Process)
{
if (((Process)sender).ExitCode < 0 && _isDisposing == false)
{
for (int i = 0; i < processList.Count; i++)
if (processList[i].Proc == (Process)sender)
processList[i].Proc = newProcess(true);
throw new SystemException("Un processus a échoué. code : " + ((Process)sender).ExitCode + "(" + ((Process)sender).StandardError.ReadToEnd() + ")");
}
}
}
// triggered when process writes on stdout.
private void on_proc_output(object sender, DataReceivedEventArgs e)
{
if (!String.IsNullOrEmpty(e.Data))
{
if(e.Data == "[end]")
{
foreach(Couple c in processList)
{
if(c.Proc == (Process)sender)
{
// resumes calling thread
c.AutoEvent.Set();
// release process
c.IsUsed = false;
}
}
}
}
}
// creates a new process and start it. Process will then be idling for input.
private Process newProcess(bool is_pool)
{
Process proc = new Process();
// hide window
proc.StartInfo.UseShellExecute = false;
//proc.StartInfo.CreateNoWindow = true;
//proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF7;
//proc.StartInfo.WorkingDirectory = GlobalDatas.Configuration.Path["map_builder"];
//proc.StartInfo.FileName = GlobalDatas.Configuration.Path["map_builder"] + "Map Builder.exe";
proc.StartInfo.WorkingDirectory = @"C:\Work\VStudio\Map Builder\release";
proc.StartInfo.FileName = @"C:\Work\VStudio\Map Builder\release\Map Builder.exe";
if(is_pool)
proc.Exited += new EventHandler(on_proc_Exit);
proc.OutputDataReceived += new DataReceivedEventHandler(on_proc_output);
proc.EnableRaisingEvents = true;
proc.Start();
proc.BeginOutputReadLine();
return proc;
}
// disposing the calss, kill the processes.
public void Dispose()
{
_isDisposing = true;
foreach (Couple c in processList)
{
c.Proc.Kill();
c.Proc.Close();
}
Console.WriteLine("all process killed");
}
/// <summary>
/// Util class to handle process and their status
/// </summary>
private class Couple
{
private Process _proc;
private bool _isUsed;
private AutoResetEvent _autoEvent;
public Couple(Process p)
{
_proc = p;
_isUsed = false;
}
public Process Proc
{
get { return _proc; }
set { _proc = value; }
}
public bool IsUsed
{
get { return _isUsed; }
set { _isUsed = value; }
}
public AutoResetEvent AutoEvent
{
get { return _autoEvent; }
set { _autoEvent = value; }
}
}
}
} |
Partager