Несколько потоков, считанных из того же файла

Моя платформа - это Windows Vista 32 с визуальным С++ express 2008.

например:

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

поток 1 читается 0-999, поток 2 читается 1000 - 2999 и т.д.

просьба привести пример на языке С.

Ответ 1

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

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

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

Ответ 2

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

Самым простым способом является простое отображение карты памяти. Затем ОС даст вам пустоту *, где файл отображается в память. Внесите это в 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);

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

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

Мне нужно задаться вопросом, почему бы вам хотелось, хотя это, скорее всего, будет работать плохо, так как ваш жесткий диск будет тратить много времени на поиск взад и вперед, а не чтение всего этого в одном (относительно) непрерывном развертке. Для небольших файлов (например, вашего примера с 4000 строк), где это может не быть такой проблемой, это не кажется проблемой.

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

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

Ответ 11

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

Ответ 13

Он хочет читать из файла в разных потоках. Я думаю, это должно быть нормально, если файл открывается как только для чтения по каждому потоку.

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