Меня немного удивляет, что никто не хочет указать автору 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>>>();
...
}
Я бы Вам советовал почитать книжки:
Энтони Уильямс. «Параллельное программирование на C++ в действии», «C++. Практика многопоточного программирования».
Сандерс Джейсон. Технология CUDA в примерах. Введение в программирование графических процессоров
Про алгоритм. Вся его суть (без всякой математики по факторизации чисел) сводится к такой реализации:
Отмечу, что диапазон значений unsigned long long не обязательно хватит для любых входных данных, поэтому не забываем о возможном переполнении.
Но вернемся к Вашему методу.
Вот вы пишете ожидания завершения потоков:
На самом деле, у Вас тут гонка данных (race condition) за общий разделяемый ресурс , поскольку каждый поток в Вашей реализации увеличивает эту переменную в самом начале своей работы (а нужно в конце, ибо мы ждем завершения!!!), и никто точно не знает, какое значение осталось в кэше потока. Для более корректного применения такого подхода нужно использовать , но в идеале я написал бы так:
Неужели Вас совершенно не удивило, что работа 1000 потоков на 8-ми ядерном процессоре быстрее, чем на графическом процессоре, у которого допустимое число потоков куда больше?
Реализация для графического процессора у Вас просто не подходящая, мягко говоря. Если писать на коленке, то в моем видении, это должно выглядеть примерно так:
Я бы Вам советовал почитать книжки:
Ну и конечно, больше практики. Успехов!