парсинг — разбирает строку c ++, используя несколько потоков

Я поместил огромный файл в строку char и сделал из нее строку c ++. Мне нужно проанализировать эту строку на основе символа-разделителя, который является пробелом, и сохранить значения в матрице. Я мог бы сделать это из одного потока, но мне нужно оптимизировать это. Поэтому я использую несколько потоков, чтобы разобрать строки из этого потока и сохранить их в матрице. Несмотря на то, что, основываясь на идентификаторе потока, я мог бы синхронно хранить проанализированные данные в матрице, но как мне синхронизировать синтаксический анализ, поскольку любой поток может быть запланирован в любое время и проанализировать строку. Вот мой код

void* parseMappedString(void* args)
{
char temp[BUFFSIZE];
long int threadID = *((long int*)args);
if (threadID  < 0)
threadID = 0;

for (int i = ((threadID) * 160); i < ((threadID+1) * 160); i++)
{
for (int j = 0; j < 4000; j++)
{
pthread_mutex_lock(&ParseMatrixMutex);
if ((matrix_str.getline(temp,BUFFSIZE, ' ')) )
{
pthread_mutex_unlock(&ParseMatrixMutex);
matrix[i][j] = parseFloat((temp));
}
else
{
pthread_mutex_unlock(&ParseMatrixMutex);
}
}
}
}

void create_threads_for_parsing(void)
{
long int i;

for (i = 0; i < 5; i++)
pthread_create(&Threads[i], NULL, parseMappedString, (void*)&i);
}

В коде, если вы видите, что всего пять потоков, и каждый поток обрабатывает 160 * 4000 элементов. И они сохраняются на основе их идентификатора потока, следовательно, в уникальном месте в матрице. таким образом, это синхронизируется. Но getline может выполняться любым потоком в любое время, поэтому поток № 5 может анализировать данные, принадлежащие первому потоку. Как мне избежать этого?

Я должен был следовать, потому что я получаю 1-4 threadids в аргументах, но никогда не 0. Это всегда приходит как некое нежелательное отрицательное значение, поэтому мне пришлось жестко закодировать его вот так.

if (threadID < 0)
threadID = 0;

0

Решение

Я поместил огромный файл в строку char и создал строку c ++

Не, std::string должен копия памяти, так что вы потеряете улучшение производительности, иначе mmap получит вас. Просто работайте с необработанной памятью как массив символов

Я мог бы сделать это из одного потока, но мне нужно оптимизировать это

Вы уверены, что несколько потоков будут оптимизировать это? Вы профилировали и подтвердили, что он определенно привязан к процессору, а не к вводу / выводу?


Если вы уверены, что есть несколько потоков, я бы предложил сделать это:

  1. Создайте N темы (это должно основываться на количестве ядер, а затем настраиваться в соответствии с результатами теста)
  2. вырезать ваш регион mmap’d в N блоки примерно одинакового размера
    • Вы можете просто искать назад & вперед для ближайшей новой строки к границе вашего блока
  3. есть каждая нить N создать свой собственный независимый выход
  4. объединить все выходы потом

Что касается ошибки в коде, я пытаюсь убедить вас не использовать: вы передаете (void*)&i в качестве аргумента функции потока. Это указатель на автоматический локальный, который выходит из области видимости в конце create_threads_for_parsingтак что это может быть случайным мусором к тому времени, когда любой поток его читает.
Даже если бы это не было случайный мусор (то есть, если create_threads_for_parsing присоединился ко всем потокам до возвращения, чтобы сохранить i по объему), было бы тот же указатель для каждой темы.

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

1

Другие решения

std::string::getline не является потокобезопасным, вы не можете использовать getline() из разных тем.

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

strncopy(matrix_str.c_str(), temp, 4000);

или используя подстрока-функция (C ++ — стиль)

std::string piece = matrix_str.substr(i,4000)

РЕДАКТИРОВАТЬ: Если ваш matrix_str это не std::string но std::sstream объект, это не будет работать, так как поток должен быть доступен по порядку. Ваш вопрос немного расплывчат в этой части …

0

Код почти полностью мьютексирован, поэтому нет смысла использовать потоки.

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

Например, разбить большую строку на 4 части и отправить ее в потоки, чтобы они могли прочитать и обработать ее, поместив результат в свое эксклюзивное место. Вывод может идти в матрицу, если нет общих ячеек, но помните о false sharing это все еще может испортить производительность.

0

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

Вы должны присоединиться ко всем потокам перед выходом из функции create_threads_for_parsing. Так как в данный момент вы передаете потокам указатель на локальную переменную в нем.

Хуже того, переменная является общей, поэтому у вас есть условие гонки. Вы делаете что-то вроде:

static const int ids = {0, 1, 2, 3, 4};

и передать указатель на соответствующую ячейку в цикле.

0
По вопросам рекламы [email protected]