I have some System.Diagnotics.Processes to run. I'd like to call the close method on them automatically. Apparently the "using" keyword does this for me.
我有一些System.Diagnotics.Processes来运行。我想自动调用close方法。显然,“using”关键字为我做了这个。
Is this the way to use the using keyword?
这是使用using关键字的方式吗?
foreach(string command in S) // command is something like "c:\a.exe"
{
try
{
using(p = Process.Start(command))
{
// I literally put nothing in here.
}
}
catch (Exception e)
{
// notify of process failure
}
}
I'd like to start multiple processes to run concurrently.
我想开始多个进程同时运行。
3 个解决方案
#1
15
using(p = Process.Start(command))
This will compile, as the Process
class implements IDisposable
, however you actually want to call the Close
method.
Logic would have it that the Dispose
method would call Close
for you, and by digging into the CLR using reflector, we can see that it does in fact do this for us. So far so good.
这将编译,因为Process类实现了IDisposable,但实际上你想要调用Close方法。逻辑会让Dispose方法为你调用Close,并且通过使用反射器挖掘CLR,我们可以看到它确实为我们做了这个。到现在为止还挺好。
Again using reflector, I looked at what the Close
method does - it releases the underlying native win32 process handle, and clears some member variables. This (releasing external resources) is exactly what the IDisposable pattern is supposed to do.
再次使用反射器,我查看了Close方法的作用 - 它释放了底层的本机win32进程句柄,并清除了一些成员变量。这(释放外部资源)正是IDisposable模式应该做的事情。
However I'm not sure if this is what you want to achieve here.
但是我不确定这是否是你想要在这里实现的。
Releasing the underlying handles simply says to windows 'I am no longer interested in tracking this other process'. At no point does it actually cause the other process to quit, or cause your process to wait.
释放底层句柄只是对Windows说'我不再对跟踪这个其他过程感兴趣了'。它决不会导致其他进程退出,或导致进程等待。
If you want to force them quit, you'll need to use the p.Kill()
method on the processes - however be advised it is never a good idea to kill processes as they can't clean up after themselves, and may leave behind corrupt files, and so on.
如果你想强制它们退出,你需要在进程上使用p.Kill()方法 - 但是请注意,杀死进程永远不是一个好主意,因为它们无法自行清理,并且可能会离开在腐败文件后面,等等。
If you want to wait for them to quit on their own, you could use p.WaitForExit()
- however this will only work if you're waiting for one process at a time. If you want to wait for them all concurrently, it gets tricky.
如果你想等待它们自己退出,你可以使用p.WaitForExit() - 但是这只有在你一次等待一个进程时才有效。如果你想同时等待它们,那就太棘手了。
Normally you'd use WaitHandle.WaitAll
for this, but as there's no way to get a WaitHandle
object out of a System.Diagnostics.Process
, you can't do this (seriously, wtf were microsoft thinking?).
通常你会使用WaitHandle.WaitAll,但由于无法从System.Diagnostics.Process中获取WaitHandle对象,所以你不能这样做(严重来说,wtf是微软思考的吗?)。
You could spin up a thread for each process, and call `WaitForExit in those threads, but this is also the wrong way to do it.
你可以为每个进程启动一个线程,并在那些线程中调用`WaitForExit,但这也是错误的方法。
You instead have to use p/invoke to access the native win32 WaitForMultipleObjects
function.
您必须使用p / invoke来访问本机win32 WaitForMultipleObjects函数。
Here's a sample (which I've tested, and actually works)
这是一个样本(我已经测试过,实际上有效)
[System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds );
static void Main( string[] args )
{
var procs = new Process[] {
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'" ) };
// all started asynchronously in the background
var handles = procs.Select( p => p.Handle ).ToArray();
WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever
}
#2
3
For reference: The using keyword for IDisposable objects:
供参考:IDisposable对象的using关键字:
using(Writer writer = new Writer())
{
writer.Write("Hello");
}
is just compiler syntax. What it compiles down to is:
只是编译器语法。它归结为:
Writer writer = null;
try
{
writer = new Writer();
writer.Write("Hello");
}
finally
{
if( writer != null)
{
((IDisposable)writer).Dispose();
}
}
using
is a bit better since the compiler prevents you from reassigning the writer reference inside the using block.
使用有点好,因为编译器阻止您在using块中重新分配writer引用。
The framework guidelines Section 9.3.1 p. 256 state:
框架指南第9.3.1节。 256状态:
CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area.
除了Dispose()之外,CONSIDER提供方法Close(),如果close是该区域中的标准术语。
In your code example, the outer try-catch is unnecessary (see above).
在您的代码示例中,不需要外部try-catch(参见上文)。
Using probably isn't doing what you want to here since Dispose() gets called as soon as p
goes out of scope. This doesn't shut down the process (tested).
使用可能不是你想要的,因为一旦p超出范围就会调用Dispose()。这不会关闭进程(已测试)。
Processes are independent, so unless you call p.WaitForExit()
they spin off and do their own thing completely independent of your program.
进程是独立的,所以除非你调用p.WaitForExit(),否则它们会脱离并完全独立于你的程序而做自己的事情。
Counter-intuitively, for a Process, Close() only releases resources but leaves the program running. CloseMainWindow() can work for some processes, and Kill() will work to kill any process. Both CloseMainWindow() and Kill() can throw exceptions, so be careful if you're using them in a finally block.
与直觉相反,对于Process,Close()仅释放资源但使程序保持运行。 CloseMainWindow()可以用于某些进程,Kill()可以杀死任何进程。 CloseMainWindow()和Kill()都可以抛出异常,所以如果你在finally块中使用它们要小心。
To finish, here's some code that waits for processes to finish but doesn't kill off the processes when an exception occurs. I'm not saying it's better than Orion Edwards, just different.
要完成,这里有一些代码等待进程完成但不会在发生异常时终止进程。我不是说它比猎户座爱德华兹更好,只是不同。
List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>();
try
{
foreach (string command in Commands)
{
processList.Add(System.Diagnostics.Process.Start(command));
}
// loop until all spawned processes Exit normally.
while (processList.Any())
{
System.Threading.Thread.Sleep(1000); // wait and see.
List<System.Diagnostics.Process> finished = (from o in processList
where o.HasExited
select o).ToList();
processList = processList.Except(finished).ToList();
foreach (var p in finished)
{
// could inspect exit code and exit time.
// note many properties are unavailable after process exits
p.Close();
}
}
}
catch (Exception ex)
{
// log the exception
throw;
}
finally
{
foreach (var p in processList)
{
if (p != null)
{
//if (!p.HasExited)
// processes will still be running
// but CloseMainWindow() or Kill() can throw exceptions
p.Dispose();
}
}
}
I didn't bother Kill()'ing off the processes because the code starts get even uglier. Read the msdn documentation for more information.
我没有打扰Kill()关闭进程,因为代码开始变得更加丑陋。有关更多信息,请阅读msdn文档。
#3
0
try
{
foreach(string command in S) // command is something like "c:\a.exe"
{
using(p = Process.Start(command))
{
// I literally put nothing in here.
}
}
}
catch (Exception e)
{
// notify of process failure
}
The reason it works is because when the exception happens, the variable p falls out of scope and thus it's Dispose method is called that closes the process is how that would go. Additionally, I would think you'd want to spin a thread off for each command rather than wait for an executable to finish before going on to the next one.
它起作用的原因是因为当异常发生时,变量p超出范围,因此调用Dispose方法来关闭进程就是这样。另外,我认为你想要为每个命令关闭一个线程,而不是等到一个可执行文件完成后才能进入下一个命令。
#1
15
using(p = Process.Start(command))
This will compile, as the Process
class implements IDisposable
, however you actually want to call the Close
method.
Logic would have it that the Dispose
method would call Close
for you, and by digging into the CLR using reflector, we can see that it does in fact do this for us. So far so good.
这将编译,因为Process类实现了IDisposable,但实际上你想要调用Close方法。逻辑会让Dispose方法为你调用Close,并且通过使用反射器挖掘CLR,我们可以看到它确实为我们做了这个。到现在为止还挺好。
Again using reflector, I looked at what the Close
method does - it releases the underlying native win32 process handle, and clears some member variables. This (releasing external resources) is exactly what the IDisposable pattern is supposed to do.
再次使用反射器,我查看了Close方法的作用 - 它释放了底层的本机win32进程句柄,并清除了一些成员变量。这(释放外部资源)正是IDisposable模式应该做的事情。
However I'm not sure if this is what you want to achieve here.
但是我不确定这是否是你想要在这里实现的。
Releasing the underlying handles simply says to windows 'I am no longer interested in tracking this other process'. At no point does it actually cause the other process to quit, or cause your process to wait.
释放底层句柄只是对Windows说'我不再对跟踪这个其他过程感兴趣了'。它决不会导致其他进程退出,或导致进程等待。
If you want to force them quit, you'll need to use the p.Kill()
method on the processes - however be advised it is never a good idea to kill processes as they can't clean up after themselves, and may leave behind corrupt files, and so on.
如果你想强制它们退出,你需要在进程上使用p.Kill()方法 - 但是请注意,杀死进程永远不是一个好主意,因为它们无法自行清理,并且可能会离开在腐败文件后面,等等。
If you want to wait for them to quit on their own, you could use p.WaitForExit()
- however this will only work if you're waiting for one process at a time. If you want to wait for them all concurrently, it gets tricky.
如果你想等待它们自己退出,你可以使用p.WaitForExit() - 但是这只有在你一次等待一个进程时才有效。如果你想同时等待它们,那就太棘手了。
Normally you'd use WaitHandle.WaitAll
for this, but as there's no way to get a WaitHandle
object out of a System.Diagnostics.Process
, you can't do this (seriously, wtf were microsoft thinking?).
通常你会使用WaitHandle.WaitAll,但由于无法从System.Diagnostics.Process中获取WaitHandle对象,所以你不能这样做(严重来说,wtf是微软思考的吗?)。
You could spin up a thread for each process, and call `WaitForExit in those threads, but this is also the wrong way to do it.
你可以为每个进程启动一个线程,并在那些线程中调用`WaitForExit,但这也是错误的方法。
You instead have to use p/invoke to access the native win32 WaitForMultipleObjects
function.
您必须使用p / invoke来访问本机win32 WaitForMultipleObjects函数。
Here's a sample (which I've tested, and actually works)
这是一个样本(我已经测试过,实际上有效)
[System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds );
static void Main( string[] args )
{
var procs = new Process[] {
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'" ) };
// all started asynchronously in the background
var handles = procs.Select( p => p.Handle ).ToArray();
WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever
}
#2
3
For reference: The using keyword for IDisposable objects:
供参考:IDisposable对象的using关键字:
using(Writer writer = new Writer())
{
writer.Write("Hello");
}
is just compiler syntax. What it compiles down to is:
只是编译器语法。它归结为:
Writer writer = null;
try
{
writer = new Writer();
writer.Write("Hello");
}
finally
{
if( writer != null)
{
((IDisposable)writer).Dispose();
}
}
using
is a bit better since the compiler prevents you from reassigning the writer reference inside the using block.
使用有点好,因为编译器阻止您在using块中重新分配writer引用。
The framework guidelines Section 9.3.1 p. 256 state:
框架指南第9.3.1节。 256状态:
CONSIDER providing method Close(), in addition to the Dispose(), if close is standard terminology in the area.
除了Dispose()之外,CONSIDER提供方法Close(),如果close是该区域中的标准术语。
In your code example, the outer try-catch is unnecessary (see above).
在您的代码示例中,不需要外部try-catch(参见上文)。
Using probably isn't doing what you want to here since Dispose() gets called as soon as p
goes out of scope. This doesn't shut down the process (tested).
使用可能不是你想要的,因为一旦p超出范围就会调用Dispose()。这不会关闭进程(已测试)。
Processes are independent, so unless you call p.WaitForExit()
they spin off and do their own thing completely independent of your program.
进程是独立的,所以除非你调用p.WaitForExit(),否则它们会脱离并完全独立于你的程序而做自己的事情。
Counter-intuitively, for a Process, Close() only releases resources but leaves the program running. CloseMainWindow() can work for some processes, and Kill() will work to kill any process. Both CloseMainWindow() and Kill() can throw exceptions, so be careful if you're using them in a finally block.
与直觉相反,对于Process,Close()仅释放资源但使程序保持运行。 CloseMainWindow()可以用于某些进程,Kill()可以杀死任何进程。 CloseMainWindow()和Kill()都可以抛出异常,所以如果你在finally块中使用它们要小心。
To finish, here's some code that waits for processes to finish but doesn't kill off the processes when an exception occurs. I'm not saying it's better than Orion Edwards, just different.
要完成,这里有一些代码等待进程完成但不会在发生异常时终止进程。我不是说它比猎户座爱德华兹更好,只是不同。
List<System.Diagnostics.Process> processList = new List<System.Diagnostics.Process>();
try
{
foreach (string command in Commands)
{
processList.Add(System.Diagnostics.Process.Start(command));
}
// loop until all spawned processes Exit normally.
while (processList.Any())
{
System.Threading.Thread.Sleep(1000); // wait and see.
List<System.Diagnostics.Process> finished = (from o in processList
where o.HasExited
select o).ToList();
processList = processList.Except(finished).ToList();
foreach (var p in finished)
{
// could inspect exit code and exit time.
// note many properties are unavailable after process exits
p.Close();
}
}
}
catch (Exception ex)
{
// log the exception
throw;
}
finally
{
foreach (var p in processList)
{
if (p != null)
{
//if (!p.HasExited)
// processes will still be running
// but CloseMainWindow() or Kill() can throw exceptions
p.Dispose();
}
}
}
I didn't bother Kill()'ing off the processes because the code starts get even uglier. Read the msdn documentation for more information.
我没有打扰Kill()关闭进程,因为代码开始变得更加丑陋。有关更多信息,请阅读msdn文档。
#3
0
try
{
foreach(string command in S) // command is something like "c:\a.exe"
{
using(p = Process.Start(command))
{
// I literally put nothing in here.
}
}
}
catch (Exception e)
{
// notify of process failure
}
The reason it works is because when the exception happens, the variable p falls out of scope and thus it's Dispose method is called that closes the process is how that would go. Additionally, I would think you'd want to spin a thread off for each command rather than wait for an executable to finish before going on to the next one.
它起作用的原因是因为当异常发生时,变量p超出范围,因此调用Dispose方法来关闭进程就是这样。另外,我认为你想要为每个命令关闭一个线程,而不是等到一个可执行文件完成后才能进入下一个命令。