Использование pthreads для ускорения обработки подсчета простых чисел от 0 до N. Правильно ли я их использую? - PullRequest
0 голосов
/ 19 марта 2019

Я пишу код, который считает простые числа от 0 до N, используя 8 потоков, чтобы ускорить процесс. Я провел некоторые исследования многопоточности в C онлайн, но я все еще не уверен, правильно ли я их использую в этом случае. Они действительно ускоряют время выполнения моей программы? Если я не ошибаюсь, pthread выполняет свои функции одновременно, нет?

#include <pthread.h>
#include <stdio.h>
#include <math.h>

#define NUM_COUNT 800
#define NUM_THREADS 8

int counter = 0; //counter to count primes
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//function to find primes
int is_prime(int n) {
    if (n < 2)return 0;
    if (n == 2)return 1;
    if (n % 2 == 0)return 0;
    for (int i=3; i < n; i += 2) {
        if (n % i == 0) return 0;
    }
    return 1;
}

void *PrintPrimes(void *threadid) {
    int thread_start, thread_end;
    int thread_id = (int)threadid; //store thread id in thread_id
    thread_start = thread_id*(NUM_COUNT/NUM_THREADS); //determine where individual thread begins searching for primes
    thread_end = thread_start+(NUM_COUNT/NUM_THREADS); //determine where thread ends searching for primes
    for(int n = thread_start; n < thread_end; n++) {
        if (is_prime(n)) {
            pthread_mutex_lock(&mutex);
            counter++;
            printf("the number of primes is currently %d\n", counter);
            pthread_mutex_unlock(&mutex);
        }
    }
    pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
    pthread_t threads[NUM_THREADS];
    for(int i = 0; i < NUM_THREADS; i++){
        pthread_create(&threads[i], NULL, PrintPrimes, (void *)i);
    }
    pthread_exit(NULL);
}

1 Ответ

4 голосов
/ 19 марта 2019

Я вижу несколько проблем с кодом:

  1. Вы никогда не вызовете pthread_join() в потоках, что означает, что ваша программа будет выходить сразу после создания потоков, а не ждатьих завершить - вероятно, не то, что вы хотите.Вы должны добавить второй цикл for, подобный этому, в конец вашей функции main():

     for(int i = 0; i < NUM_THREADS; i++) {
         pthread_join(&threads[i], NULL);
     }
    
  2. Вызов pthread_exit() в main() не нужен, вы можетеизбавиться от этого.(Он предназначен для вызова из порожденной pthread, чтобы вызвать выход потока, нет смысла вызывать его из основного потока)

  3. Вызов printf() из ваших потоков 'Цикл вычислений значительно замедлит вычисления (до такой степени, что вы вообще больше не измеряете производительность ваших реальных вычислений, скорее вы действительно измеряете только скорость, с которой printf() и подсистема stdout выполняются)

  4. Сохранение общего / глобального counter, который вы должны защищать мьютексом каждый раз, когда вы находите новое простое число, не очень эффективно;Лучше объявить локальную / неделимую встречную переменную для каждого потока и увеличить ее.Затем, в конце выполнения потока, вы можете добавить локальный счетчик потока к общему / глобальному счетчику всего один раз и, таким образом, избежать оплаты штрафа за синхронизацию, который приходит с последовательностью lock () / unlock () более одного раза.за нитку.

...