【问题标题】:why threading not working?为什么线程不起作用?
【发布时间】:2012-08-15 16:24:37
【问题描述】:

这是我的代码:

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 部分)

我不明白为什么

谢谢

【问题讨论】:

  • 它是如何工作的?如果您有多个线程写入文件,您将无序写入文件。

标签: c# .net multithreading .net-4.0 parallel-processing


【解决方案1】:

在您的代码中;

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);
});

buffer 是一个共享变量,所以所有线程都会共享它。例如,线程 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)都不能保证是线程安全的。换句话说,即使你解决了缓冲区问题,也不能保证一切都会好起来。

【讨论】:

  • 他的代码的基本问题是他试图通过使用多个线程访问相同的数据流来更快地复制文件。虽然您的回答指向一个问题,但它并不能解决更大的问题。
  • @NikolaRadosavljević 虽然不太可能,但这是我们正在读/写的内存映射文件。如果页面被调出,让另一个线程接管并在等待分页时复制下一页实际上可能会加快操作速度。虽然在实践中同意,但这可能不会加快任何速度。
  • @NikolaRadosavljević 在阅读您的输入并仔细检查文档后更新了我的答案。好电话。
【解决方案2】:

您复制文件的方法不好。除了 Joachim Isaksson 描述的问题之外,问题是您同时从多个线程访问文件流。这意味着可能会发生一个线程 T1 读取数据,然后调度程序将控制权传递给线程 T2,线程 T2 读取数据然后将其写入目标。当控制权返回到 T1 并写入读取数据时,您将得到一个损坏的文件。 没有理由使用并发来复制文件,因为 CPU 不是此操作的瓶颈。你不会得到更快的结果,你只会浪费 CPU 周期。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-18
    • 2013-04-02
    • 2015-06-07
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多