В этом сценарии у меня есть вектор векторов целых чисел без знака, которые я обрабатываю. В обычном случае будет 256 векторов из 1048576 целых чисел без знака. Я хочу использовать API pThread С++, чтобы каждый pthread выполнял следующую работу над назначенным ему подсписком целых чисел без знака (длиной 1048576).
for(int i = 0; i < list_size; i++)
{
int *arg = (int *) malloc(sizeof(*arg));
*arg = i;
thread_err = pthread_create(&(threads[i]), NULL, &Heap_Build, arg);
if (thread_err != 0)
printf("\nCan't create thread :[%s]", strerror(thread_err));
}
Как видно из приведенного выше кода, я просто генерирую столько потоков, сколько есть подсписков в основном списке, и я отправляю их каждый со значением индекса в основной вектор подсписков, чтобы они знали, какие подсписки. список, который они эффективно обрабатывают.
void* Heap_Build(void *arg)
{
int main_list_index = *((int *)arg);
//pthread_mutex_lock( &mutex1 );
num_of_nodes = 0;
pheapType heap = pheapType(malloc((k+usage_offset) * sizeof(heapType)));
unsigned int sublist_value;
for(int i = 0; i < k; i++)
{
sublist_value = main_list.at(main_list_index).at(i);
Heap_Insert_Node(heap, sublist_value);
}
for(int i = k; i < sub_list_size; i++)
{
sublist_value = main_list.at(main_list_index).at(i);
if(sublist_value < heap[usage_offset])
{
Heap_Update_Key_CPU(heap, 0, sublist_value);
}
}
//pthread_mutex_unlock( &mutex1 );
cpu_results[main_list_index] = heap[usage_offset];
free(heap);
}
Примечание
num_of_nodes — количество узлов, в настоящее время вставленных в структуру кучи. Он устанавливается равным 0 перед созданием каждой кучи и используется операциями update_key и insert_node для определения индекса в массиве кучи для размещения значения.
sublist_value — текущее значение обрабатываемого подсписка.
Приведенная выше функция по существу выделяет массив памяти для создания кучи из первых «k» элементов в подсписке, который обрабатывает поток. Затем он обрабатывает оставшиеся элементы, используя операцию ключа обновления кучи.
Таким образом, каждому потоку присваивается индекс подсписка в глобальном векторе подсписков целых чисел без знака. Он создает кучу из первых k-х элементов в подсписке, а затем обрабатывает оставшиеся k-е элементы в подсписках на основе той кучи, которую он создал.
Я могу заставить все работать нормально, если я создам 2 ^ 8 подсписков размером 2 ^ 8 или 256 потоков, обрабатывающих 256 подсписков из 256 целых чисел или даже 1 подсписок из 2 ^ 20 целых чисел, но в тестовом примере 2^8 подсписков из 2^20 целых чисел. Программа либо имеет ошибку сегментации, либо просто прерывается.
Если я раскомментирую блокировки мьютекса. Любой случай работает нормально, но, к сожалению, он будет выполнять вычисления последовательно. Я не уверен, в чем может быть проблема, в основном потому, что я новичок в работе с потоками POSIX. Очевидно, проблема связана с тем, что количество целых чисел в подсписке слишком велико в сочетании с количеством потоков и, возможно, состоянием гонки, но я не уверен, как определить критические области в общем вычислении, а не просто установка блокировки мьютекса на все вычисления и удаление всего параллелизма.
При необходимости я мог бы предоставить код для двух функций кучи, используемых в Heap_Build, но я не пытаюсь увязнуть в этом вопросе слишком большим количеством кода.
РЕДАКТИРОВАТЬ: я считаю, что проблема в приведенном выше коде заключается в том, что все потоки ссылаются на одно и то же пространство памяти, «кучу», вместо того, чтобы каждый поток выделял собственную структуру кучи. Поэтому, когда первый поток, завершающий вычисления, освобождает пространство памяти, выделенное для «кучи», другие потоки ссылаются на недопустимую область памяти, что приводит к ошибке сегментации. Если я удалю строку «свободно (куча)», ошибка исчезнет, но значения будут неверными. Я не уверен, как это исправить, я думаю, что для этого потребуется предоставить каждому pthread собственное пространство кучи памяти для работы, чтобы ни один из потоков не наступал на данные друг друга, но я не совсем уверен, как это сделать это.