Search
Write a publication
Pull to refresh
0
0
Send message
Меня немного удивляет, что никто не хочет указать автору Stalker31 на его ошибки. Попробую это сделать. (Если заметите ошибки и у меня, поправляйте, буду только «ЗА!»).

Про алгоритм. Вся его суть (без всякой математики по факторизации чисел) сводится к такой реализации:
void thread_task(size_t number, size_t max_degree, size_t tid, size_t* result)
{
   // tid - индекс потока
   size_t val = 1;
   for (size_t deg = 1; deg < max_degree; ++deg) {
      val *= tid;
      if (val == number)
         result[tid] = deg;
   }
}

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

Но вернемся к Вашему методу.
Вот вы пишете ожидания завершения потоков:
thread *T = new thread[size];
Running_thread_counter = 0;
for (int i = 0; i < size; i++) {
   T[i] = thread(Upload_to_CPU, Number, Stepn, Stop, INPUT, max, i);
   T[i].detach();
}
while (Running_thread_counter < size - 1);//дождаться завершения выполнения всех потоков
// <= только не (size-1), а size

// <= А где у нас удаление ресурсов в виде delete[] T???


На самом деле, у Вас тут гонка данных (race condition) за общий разделяемый ресурс
Running_thread_counter
, поскольку каждый поток в Вашей реализации увеличивает эту переменную в самом начале своей работы (а нужно в конце, ибо мы ждем завершения!!!), и никто точно не знает, какое значение осталось в кэше потока. Для более корректного применения такого подхода нужно использовать
atomic<int> Running_thread_counter
, но в идеале я написал бы так:
for (int i = 0; i < size; i++) {
   T[i] = thread(Upload_to_CPU, Number, Stepn, Stop, INPUT, max, i);
}
for (int i = 0; i < size; i++) {
   T[i].join();   // <= ждем фактического завершения работы потока
}


Неужели Вас совершенно не удивило, что работа 1000 потоков на 8-ми ядерном процессоре быстрее, чем на графическом процессоре, у которого допустимое число потоков куда больше?

Реализация для графического процессора у Вас просто не подходящая, мягко говоря. Если писать на коленке, то в моем видении, это должно выглядеть примерно так:

__constant__ unsigned long long number, max_degree;
__shared__ unsigned long long buffer[1024];

__global__ void kernel(int* result)
{
   unsigned long long tid = threadId.x;
   unsigned long long val = 1;

   for (unsigned long long deg = 1; deg < max_deg; ++deg) {
      val *= tid;
      if (val == number) {
         buffer[tid] = deg;
         break;
      }
   }
   result[tid] = buffer[tid];
}

int main()
{
   ...
   // CUDA оперирует понятием варпа (cuda core в спецификации видеокарт, 32 потока), 
   // поэтому их число лучше делать кратным 32
   kernel<<<1, 1024>>>();  
   ...
}


Я бы Вам советовал почитать книжки:
  1. Энтони Уильямс. «Параллельное программирование на C++ в действии», «C++. Практика многопоточного программирования».
  2. Сандерс Джейсон. Технология CUDA в примерах. Введение в программирование графических процессоров

Ну и конечно, больше практики. Успехов!

Information

Rating
Does not participate
Registered
Activity