WedX - журнал о программировании и компьютерных науках

Создание и управление отдельными кучами с помощью pThreads

В этом сценарии у меня есть вектор векторов целых чисел без знака, которые я обрабатываю. В обычном случае будет 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 собственное пространство кучи памяти для работы, чтобы ни один из потоков не наступал на данные друг друга, но я не совсем уверен, как это сделать это.


  • Обратите внимание на раздел, выделенный жирным шрифтом вверху. 28.03.2014

Ответы:


1

В коде, который вы показали, каждый поток, выполняющий функцию Heap_Build, выделяет для работы свою собственную структуру кучи:

pheapType heap = pheapType(malloc((k+usage_offset) * sizeof(heapType)));

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

Однако ваш код не проверяет, действительно ли была выделена память. 256 векторов из 1048576 целых чисел уже потребляют 2^(20+8+2)=2^30 или 1 ГБ памяти. Если код 32-битный и размер выделения значителен, может случиться так, что не будет свободного блока памяти достаточной длины. Тогда в каком-то потоке heap может быть NULL, и манипуляции с такой "кучей" скорее всего приведут к краху.

Другая возможность — гонки данных в Heap_Insert_Node и/или Heap_Update_Key_CPU, если эти функции имеют побочные эффекты (например, модифицируют некоторые глобальные переменные).

29.03.2014
Новые материалы

Объяснение документов 02: BERT
BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

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

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


Для любых предложений по сайту: [email protected]