Я поместил огромный файл в строку 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;
Я поместил огромный файл в строку char и создал строку c ++
Не, std::string
должен копия памяти, так что вы потеряете улучшение производительности, иначе mmap получит вас. Просто работайте с необработанной памятью как массив символов
Я мог бы сделать это из одного потока, но мне нужно оптимизировать это
Вы уверены, что несколько потоков будут оптимизировать это? Вы профилировали и подтвердили, что он определенно привязан к процессору, а не к вводу / выводу?
Если вы уверены, что есть несколько потоков, я бы предложил сделать это:
Что касается ошибки в коде, я пытаюсь убедить вас не использовать: вы передаете (void*)&i
в качестве аргумента функции потока. Это указатель на автоматический локальный, который выходит из области видимости в конце create_threads_for_parsing
так что это может быть случайным мусором к тому времени, когда любой поток его читает.
Даже если бы это не было случайный мусор (то есть, если create_threads_for_parsing
присоединился ко всем потокам до возвращения, чтобы сохранить i
по объему), было бы тот же указатель для каждой темы.
Чтобы безопасно передать отдельный целочисленный идентификатор каждому потоку, вы должны выделить отдельное целое число для каждого потока и передать его адрес. Либо это, либо возиться с intptr_t
,
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
объект, это не будет работать, так как поток должен быть доступен по порядку. Ваш вопрос немного расплывчат в этой части …
Код почти полностью мьютексирован, поэтому нет смысла использовать потоки.
Идея палатализации заключается в том, чтобы сделать работу фактически выполненной одновременно. Для этого вы должны сократить обмен данными, в идеале до нуля.
Например, разбить большую строку на 4 части и отправить ее в потоки, чтобы они могли прочитать и обработать ее, поместив результат в свое эксклюзивное место. Вывод может идти в матрицу, если нет общих ячеек, но помните о false sharing
это все еще может испортить производительность.
Что касается странной части с идентификатором 0: я думал, что опубликованный код является просто демонстрацией, но вы можете буквально использовать его.
Вы должны присоединиться ко всем потокам перед выходом из функции create_threads_for_parsing. Так как в данный момент вы передаете потокам указатель на локальную переменную в нем.
Хуже того, переменная является общей, поэтому у вас есть условие гонки. Вы делаете что-то вроде:
static const int ids = {0, 1, 2, 3, 4};
и передать указатель на соответствующую ячейку в цикле.