2011-07-20 46 views
2

我正在使用System.Diagnostics.Process类将wav文件转换为分离过程中的mp3文件。 ,做这样的工作方法:我很担心GC是否可以对System.Diagnostics.Process实例进行垃圾收集?

public void ConvertWavToMp3 (TempFile srcFile, string title, Action<TempFile, Exception> complete) 
    { 
     var argument_fmt = "-S --resample 16 --tt {0} --add-id3v2 {1} {2}"; 
     var dstFile = new TempFile(Path.GetTempFileName()); 

     var proc = new System.Diagnostics.Process(); 

     proc.EnableRaisingEvents = true; 
     proc.StartInfo.UseShellExecute = false; 
     proc.StartInfo.FileName = "lame"; 
     proc.StartInfo.Arguments = String.Format (argument_fmt, 
                title, 
                srcFile.Path, 
                dstFile.Path); 

     proc.Exited += delegate(object sender, EventArgs e) { 
      proc.WaitForExit(); 
      srcFile.Delete(); 
      complete(dstFile, null); 
     }; 

     proc.Start(); 
    } 

因为PROC只是一个局部变量,理论上不存在了该方法返回时。因此,proc可以被垃圾收集,回调函数完成将永远不会被调用。

但我并不是真的想记录某处的proc,并在该进程退出后进行处理,因为这会暴露如何实现wav到mp3转换的内部机制。

我对GC的担心有效吗?如果GC是潜在的问题,有没有什么办法可以阻止它,而不必用这种方法返回proc?

顺便说一句,我在linux上使用Mono。

编辑

感谢的答复。我确认我需要保留一个过程的副本。因此,这里是我所做的:

public class LameConverter : IAudioConverter 
{ 
    // We need to store a reference to the process in case it was GCed. 
    IList<Process> _ProcList = new List<Process>(); 

    public void ConvertWavToMp3 (TempFile srcFile, string title, Action<TempFile, Exception> complete) 
    { 
        // .. skipped .. 
     proc.Exited += delegate(object sender, EventArgs e) { 
      lock (this) { 
       _ProcList.Remove(proc);    
      } 
      proc.Dispose(); 
      srcFile.Delete(); 
      complete(dstFile, null); 
     }; 

     proc.Start(); 

     lock (this) { 
      _ProcList.Add(proc); 
     } 
    } 
} 

只要调用者持有至LameConverter参考,我不需要担心GC了。

回答

2

在应用程序中没有根的任何对象都是垃圾收集的候选对象。为了确保您的回调火灾,您将需要找到一些地方来存储对proc的引用,否则您将会有未定义的行为。

你的情况的一个选择是返回一个封装了proc而不通过公共接口暴露的对象。不幸的是,在您的情况下,您必须将一些底层实现泄露给ConvertWavToMp3的调用者,以确保发生期望的行为。

+1

非常好的观察,虽然有一件事情发生,因为Proc使用内部资源,被其他内部代码引用它可能不会被GCed,但你说他应该保持该引用某处,以免进程退出和处理程序花费太长时间(除非不再需要proc引用) –

0

这是一个可以工作的替代代码示例。但是,在进程执行期间,它将阻止对ConvertWavToMp3(...)的调用。可能不是你想要的。

public void ConvertWavToMp3 (TempFile srcFile, string title, Action<TempFile, Exception> complete) 
{ 
    var argument_fmt = "-S --resample 16 --tt {0} --add-id3v2 {1} {2}"; 
    var dstFile = new TempFile(Path.GetTempFileName()); 

    var proc = new System.Diagnostics.Process(); 

    proc.EnableRaisingEvents = true; 
    proc.StartInfo.UseShellExecute = false; 
    proc.StartInfo.FileName = "lame"; 
    proc.StartInfo.Arguments = String.Format (argument_fmt, 
               title, 
               srcFile.Path, 
               dstFile.Path); 

    using(var wh = new System.Threading.ManualResetEvent(false)) 
    { 
     proc.Exited += delegate(object sender, EventArgs e) { 
      proc.WaitForExit(); 
      srcFile.Delete(); 
      complete(dstFile, null); 
      wh.Set(); 
     }; 


     proc.Start(); 
     wh.WaitOne(); 
    } 
} 

就像我说的,这可能不是你想要的,除非你是在一个控制台应用程序。如果你在一个GUI应用程序中,请保留对你的proc的引用。例如:

public class MyForm : Form 
{ 
    // other form stuff 

    private System.Diagnostics.Process _encoderProc; 

    private void doEncode_Click(object sender, EventArgs e) 
    { 
     var argument_fmt = "-S --resample 16 --tt {0} --add-id3v2 {1} {2}"; 
     var dstFile = new TempFile(Path.GetTempFileName()); 

     var proc = new System.Diagnostics.Process(); 

     proc.EnableRaisingEvents = true; 
     proc.StartInfo.UseShellExecute = false; 
     proc.StartInfo.FileName = "lame"; 
     proc.StartInfo.Arguments = String.Format (argument_fmt, 
                title, 
                srcFile.Path, 
                dstFile.Path); 

     proc.Exited += delegate(object sender, EventArgs e) { 
      proc.WaitForExit(); 
      srcFile.Delete(); 

      this.BeginInvoke((MethodInvoker)delegate { 
       // INSERT CODE HERE: your UI-related stuff that you want to do with dstFile 
       this._encoderProc = null; 
      }); 
     }; 

     proc.Start(); 
     this._encoderProc = proc; 
    } 
} 

请注意使用BeginInvoke(...)。如果你打算做UI相关的东西,它需要在UI线程上,并且该事件不会在UI线程上触发。希望这能让你朝着正确的方向前进。