2011-07-20 80 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線程上觸發。希望這能讓你朝着正確的方向前進。