多个线程从同一个文件读取

时间:2009-05-05 05:30:47

标签: c++ c file-io

我的平台是windows vista 32,带有visual c ++ express 2008。

例如:

如果我有一个包含4000个字节的文件,我可以同时从文件中读取4个线程吗?每个线程访问文件的不同部分。

线程1读取0-999,线程2读取1000 - 2999等

请用C语言举例。

13 个答案:

答案 0 :(得分:21)

如果您不写信给他们,则无需处理同步/竞争状况。

只需打开带有共享阅读的文件作为不同的句柄,一切都会起作用。 (即,您必须在线程的上下文中打开文件,而不是共享相同的文件句柄。)

#include <stdio.h>
#include <windows.h>

DWORD WINAPI mythread(LPVOID param)
{
    int i = (int) param;
    BYTE buf[1000];
    DWORD numread;

    HANDLE h = CreateFile("c:\\test.txt", GENERIC_READ, FILE_SHARE_READ,
        NULL, OPEN_EXISTING, 0, NULL);

    SetFilePointer(h, i * 1000, NULL, FILE_BEGIN);
    ReadFile(h, buf, sizeof(buf), &numread, NULL); 
    printf("buf[%d]: %02X %02X %02X\n", i+1, buf[0], buf[1], buf[2]);

    return 0;
}

int main()
{
    int i;
    HANDLE h[4];

    for (i = 0; i < 4; i++)
        h[i] = CreateThread(NULL, 0, mythread, (LPVOID)i, 0, NULL);

    // for (i = 0; i < 4; i++) WaitForSingleObject(h[i], INFINITE);
    WaitForMultipleObjects(4, h, TRUE, INFINITE);

    return 0;
}

答案 1 :(得分:4)

诚实地,甚至没有一个大问题。

到目前为止,最简单的方法是对文件进行内存映射。操作系统将为您提供一个void *,其中文件被映射到内存中。将其转换为char [],并确保每个线程使用不重叠的子数组。

void foo(char* begin, char*end) { /* .... */ }
void* base_address = myOS_memory_map("example.binary");
myOS_start_thread(&foo, (char*)base_address, (char*)base_address + 1000);
myOS_start_thread(&foo, (char*)base_address+1000, (char*)base_address + 2000);
myOS_start_thread(&foo, (char*)base_address+2000, (char*)base_address + 3000);

答案 2 :(得分:2)

您当然可以从数据结构中读取多个线程,如果正在进行任何编写,则可能会出现竞争条件。

要避免这种竞争条件,您需要定义线程可以读取的边界,如果您有明确数量的数据段和明确数量的线程来匹配这些,那么这很容易。

至于C中的示例,您需要提供更多信息,例如您正在使用的线程库。首先尝试,然后我们可以帮助您解决任何问题。

答案 3 :(得分:2)

我认为这样做没有任何实际优势 您可能有多个线程从设备读取,但您的瓶颈不是CPU,而是磁盘IO速度。

如果你不小心,你甚至可能会减慢进程的速度(但你需要对其进行测量才能确定)。

答案 4 :(得分:2)

Windows支持重叠I / O,允许单个线程异步排队多个I / O请求以获得更好的性能。只要您访问的文件支持搜索(即这不是管道),这可以被多个线程同时使用。

FILE_FLAG_OVERLAPPED传递给CreateFile()允许在同一文件句柄上同时进行读写操作;否则,Windows序列化它们。使用OVERLAPPED结构的OffsetOffsetHigh成员指定文件偏移量。

有关详细信息,请参阅Synchronization and Overlapped Input and Output

答案 5 :(得分:1)

最简单的方法是在每个并行实例中打开文件,但只需将其打开即可。

那些认为可能存在IO瓶颈的人可能是错的。任何现代操作系统都会缓存文件读取。这意味着第一次读取文件时速度最慢,任何后续读取都会很快。一个4000字节的文件甚至可以放在处理器的缓存中。

答案 6 :(得分:0)

如果他们所做的只是阅读,你不应该做任何特别聪明的事情。显然,只要您不完全锁定它,您可以根据需要多次并行读取它。写作显然是另一回事......

我不得不想知道你为什么要这样做 - 它可能会表现不佳,因为你的硬盘将浪费大量时间来回寻找,而不是在一次(相对)不间断的扫描中阅读。对于可能不是这样的问题的小文件(例如你的4000行示例),它似乎不值得麻烦。

答案 7 :(得分:0)

虽然我不确定它是否值得付出努力。您是否考虑在单个线程中将整个文件读入内存,然后允许多个线程访问该数据?

答案 8 :(得分:0)

阅读:无需锁定文件。只需将文件打开为只读或共享读取

即可

写入:使用互斥锁确保文件仅由一个人写入。

答案 9 :(得分:0)

正如其他人已经注意到的那样,只要拥有自己的文件描述符/句柄,就可以从同一个文件中读取多个线程。但是,我对你的动机有点好奇。为什么要读取并行文件?如果您只是将文件读入内存,那么您的瓶颈可能就是磁盘本身,在这种情况下,多个线程根本不会帮助您(它只会使您的代码混乱)。

与优化时一样,在您(1)有一个易于理解,有效的解决方案,以及(2)您已经测量了代码以了解应该优化的位置之前,您不应该尝试它。

答案 10 :(得分:0)

std::mutex mtx;

void worker(int n)
{
    mtx.lock();

    char * memblock;

    ifstream file ("D:\\test.txt", ios::in);

    if (file.is_open())
    {
        memblock = new char [1000];
        file.seekg (n * 999, ios::beg);
        file.read (memblock, 999);
        memblock[999] = '\0';

        cout << memblock << endl;

        file.close();
        delete[] memblock;
    }
    else 
        cout << "Unable to open file";
    mtx.unlock();
}


int main()
{
    vector<std::thread> vec;
    for(int i=0; i < 3; i++)
    {
        vec.push_back(std::thread(&worker,i));
    }

    std::for_each(vec.begin(), vec.end(), [](std::thread& th)
    {
        th.join();
    });
    return 0;
}

答案 11 :(得分:-1)

您需要一种方法来同步这些线程。互斥锁http://en.wikipedia.org/wiki/Mutual_exclusion

有不同的解决方案

答案 12 :(得分:-1)

他想在不同的帖子中读取文件。如果文件以每个线程的只读方式打开,我想这应该没问题。

我希望你不要为性能而这样做,因为你必须扫描文件的大部分内容以获取每个线程中的换行符。