2012-08-15 31 views
0

這裏是我的代碼:爲什麼線程無法正常工作?

using System; 

using System.Collections; 
using System.Collections.Generic; 
using System.Collections.Concurrent; 
using System.Linq; 

using System.Threading; 
using System.Threading.Tasks; 

using System.IO; 
using System.IO.MemoryMappedFiles; 

namespace CopyFile 
{ 
class Program 
{ 
    static void Main() 
    { 
     long length = 0; 
     byte[] buffer; 
     string source_path, dest_path; 
     source_path = Console.ReadLine(); 
     dest_path = Console.ReadLine(); 
     FileInfo fi = new FileInfo(source_path); 
     length = (int)fi.Length; 
     // Create disk file 
     using (FileStream fs = File.Create(dest_path)) 
     { 
      fs.Close(); 
     } 
     // Create unnamed MMF 
     var mmf1 = MemoryMappedFile.CreateFromFile(source_path, FileMode.OpenOrCreate, null, length); 
     // Create reader to MMF 
     var reader = mmf1.CreateViewAccessor(0, length, MemoryMappedFileAccess.Read); 
     // Create unnamed MMF 
     var mmf2 = MemoryMappedFile.CreateFromFile(dest_path, FileMode.Create, null, length); 
     // Create writer to MMF 
     var writer = mmf2.CreateViewAccessor(0, length, MemoryMappedFileAccess.Write); 

     int read_block = int.Parse(Math.Min(length, 512 * 1024).ToString());//4k 
     int end_read_block = int.Parse(length.ToString()) % read_block; 

     int[] offset_array = new int[int.Parse((length - read_block).ToString())/read_block]; 
     for (int offset = 0,i=0; i < int.Parse((length - read_block).ToString())/read_block; i++,offset += read_block) 
     { 
      offset_array[i] = offset; 
     } 

     /* 
     Parallel.ForEach<int>(offset_array, offset => 
     { 
      // Read from MMF 
      buffer = new byte[read_block]; 
      reader.ReadArray<byte>(offset, buffer, 0, read_block); 
      // Write to MMF 
      writer.WriteArray<byte>(offset, buffer, 0, read_block); 
     }); 
     */ 
     foreach (int offset in offset_array) 
     { 
      // Read from MMF 
      buffer = new byte[read_block]; 
      reader.ReadArray<byte>(offset, buffer, 0, read_block); 
      // Write to MMF 
      writer.WriteArray<byte>(offset, buffer, 0, read_block); 
     } 

     buffer = new byte[end_read_block]; 
     reader.ReadArray<byte>(length - end_read_block, buffer, 0, end_read_block); 
     // Write to MMF 
     writer.WriteArray<byte>(length - end_read_block, buffer, 0, end_read_block); 

    } 
} 
} 

我嘗試複製一個文件,並將其粘貼到另一個位置 它正在

但是當我嘗試使用Parallel.foreach或時的Parallel.For複製一個文件 複製的文件與源文件不同

(我評論Parallel.foreach部分)

我不明白爲什麼

謝謝

+1

它將如何工作?如果您有多個線程寫入它,您將會寫入該文件。 – steveg89 2012-08-15 16:27:44

回答

2

在你的代碼中;

Parallel.ForEach<int>(offset_array, offset => 
{ 
    // Read from MMF 
    buffer = new byte[read_block]; 
    reader.ReadArray<byte>(offset, buffer, 0, read_block); 
    // Write to MMF 
    writer.WriteArray<byte>(offset, buffer, 0, read_block); 
}); 

bufferbuffer是一個共享變量,所以所有的線程都會共享它。例如,線程1將分配緩衝區,從文件讀取,線程2將重新分配緩衝區並讀取文件,線程1將寫入線程2的緩衝區的內容。

爲了使它工作得更好,使緩衝區成爲循環中的局部變量,a'la;

Parallel.ForEach<int>(offset_array, offset => 
{ 
    // Read from MMF 
    byte[] buffer = new byte[read_block]; 
    reader.ReadArray<byte>(offset, buffer, 0, read_block); 
    // Write to MMF 
    writer.WriteArray<byte>(offset, buffer, 0, read_block); 
}); 

這將允許所有線程擁有自己的本地緩衝區。

看着documentation雖然看起來很黯淡,但任何實例方法(ReadArray/WriteArray)都不能保證是線程安全的。換句話說,即使你解決了緩衝區問題,也不能保證事情會發揮作用。

+0

他的代碼的基本問題是他試圖通過使用多個線程訪問相同的數據流來更快地複製文件。雖然你的答案指向一個問題,但它並不能解決更大的問題。 – 2012-08-15 16:37:49

+0

@NikolaRadosavljević雖然不太可能,但這是一個我們正在讀/寫的內存映射文件。如果頁面被換頁,讓另一個線程接管並在等待頁面時複製下一頁可能實際上加快了操作速度。但在實踐中同意,這可能不會加快速度。 – 2012-08-15 16:43:00

+0

@NikolaRadosavljević在閱讀您的輸入並仔細檢查文檔後更新了我的答案。好決定。 – 2012-08-15 16:49:07

0

您的複製文件的方法不好。除了Joachim Isaksson描述的問題之外,問題是您正在同時從多個線程訪問文件流。這意味着可能發生一個線程T1讀取數據,然後調度程序將控制傳遞給線程T2,線程T2讀取數據並將其寫入目標。當控制返回到T1並寫入讀取數據時,您將收到損壞的文件。 沒有理由使用併發來複制文件,因爲CPU不是此操作的瓶頸。你不會得到更快的結果,你只會浪費CPU週期。

相關問題