Чтение нескольких потоков из одного файла - PullRequest
10 голосов
/ 05 мая 2009

Моя платформа - Windows Vista 32, с Visual C ++ Express 2008.

например:

если у меня есть файл, содержащий 4000 байтов, могу ли я прочитать 4 потока из файла одновременно? и каждый поток обращается к отдельному разделу файла.

нить 1 - 0-999, нить 2 - 1000 - 2999 и т. Д.

приведите пример на языке С.

Ответы [ 13 ]

21 голосов
/ 05 мая 2009

Если вы не пишете им, нет необходимости заботиться о состоянии синхронизации / гонки.

Просто откройте файл с общим чтением разными ручками, и все будет работать. (т. е. вы должны открыть файл в контексте потока, а не использовать тот же дескриптор файла).

#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;
}
4 голосов
/ 05 мая 2009

Нет даже большой проблемы запись в один файл, честно говоря.

Безусловно, самый простой способ - просто отобразить файл в памяти. Затем ОС выдаст вам void *, где файл отображается в памяти. Приведите это к символу [] и убедитесь, что каждый поток использует неперекрывающиеся подмассивы.

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 голосов
/ 05 мая 2009

Windows поддерживает перекрывающиеся операции ввода-вывода, что позволяет одному потоку асинхронно ставить в очередь несколько запросов ввода-вывода для повышения производительности. Вероятно, это может быть использовано несколькими потоками одновременно, если файл, к которому вы обращаетесь, поддерживает поиск (т. Е. Это не канал).

Передача FILE_FLAG_OVERLAPPED в CreateFile() позволяет одновременное чтение и запись для одного и того же дескриптора файла; в противном случае Windows сериализует их. Укажите смещение файла, используя элементы Offset и OffsetHigh структуры OVERLAPPED.

Для получения дополнительной информации см. Синхронизация и перекрывающиеся входы и выходы .

2 голосов
/ 05 мая 2009

Я не вижу реального преимущества в этом.
У вас может быть несколько потоков, считывающих данные с устройства, но узким местом будет не процессор, а скорость дискового ввода-вывода.

Если вы не будете осторожны, вы можете даже замедлить процессы (но вам нужно будет измерить это, чтобы знать наверняка).

2 голосов
/ 05 мая 2009

Вы, конечно, можете иметь несколько потоков, читающих из структуры данных, условия гонки могут возникнуть, если происходит какая-либо запись .

Чтобы избежать таких условий гонки, вам нужно определить границы, которые могут прочитать потоки, если у вас есть явное количество сегментов данных и явное количество потоков для их сопоставления, тогда это просто.

Как и в примере на C, вам нужно будет предоставить дополнительную информацию, например, используемую вами библиотеку потоков. Сначала попытайтесь, затем мы поможем вам решить любые проблемы.

1 голос
/ 17 марта 2011

Самый простой способ - открыть файл в каждом параллельном экземпляре, но просто открыть его только для чтения.

Люди, которые говорят, что может быть узкое место IO, вероятно, ошибаются. Любая современная операционная система кеширует файл, читает. Это означает, что первое чтение файла будет самым медленным, а последующие чтения будут молниеносными. 4000-байтовый файл может даже находиться внутри кеша процессора.

0 голосов
/ 02 декабря 2015
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;
}
0 голосов
/ 05 мая 2009

Как уже отмечали другие, не существует внутренней проблемы чтения нескольких потоков из одного и того же файла, если у них есть свой дескриптор / дескриптор файла. Тем не менее, мне немного любопытно ваши мотивы . Почему вы хотите прочитать файл в параллель? Если вы только читаете файл в память, скорее всего, узким местом является сам диск, и в этом случае несколько потоков вам совсем не помогут (это просто загромождает ваш код).

И как всегда при оптимизации, вы не должны пытаться делать это, пока у вас (1) не будет простого для понимания, работающего решения и (2) вы измерили свой код, чтобы узнать, где вы должны оптимизировать.

0 голосов
/ 05 мая 2009

Чтение: нет необходимости блокировать файл. Просто откройте файл как доступный только для чтения или для общего доступа

Запись: используйте мьютекс, чтобы обеспечить запись в файл только одному человеку.

0 голосов
/ 05 мая 2009

Это возможно, хотя я не уверен, что это будет стоить усилий. Рассматривали ли вы чтение всего файла в память в пределах одного потока, а затем разрешить нескольким потокам доступ к этим данным?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...