Рабочие потоки и синхронизация потоков контроллера - PullRequest
0 голосов
/ 10 декабря 2011

У меня проблемы с правильной синхронизацией рабочих потоков и потоков посредника.Проблема, которую я пытаюсь решить, - найти файлы с наибольшим простым числом 10, используя до 10 потоков.1 поток является однопоточным, а все, что больше, чем многопоточным.

Проблема заключается в том, что работник сообщает помощнику, что он нашел новое простое число.Фасилитатор может игнорировать его, если число незначительно, или сигнализировать об обновлении всех потоков my_latest_lgprime, если это важно.Я все время застреваю в своем мозгу и в коде.

Задача должна быть выполнена с использованием посредника и синхронизации.

Вот что у меня есть:

Рабочий:

void* worker(void* args){
     w_pack* package = (w_pack*) args;
     int i, num;
     char text_num[30];
     *(package->fac_prime) = 0;
     for(i = 0; i<package->file_count; i++){
          int count = 1000000; //integers per file
          FILE* f = package->assigned_files[i];
          while(count != 0){
               fscanf(f, "%s", text_num);
               num = atoi(text_num);
               pthread_mutex_lock(&lock2);
               while(update_ready != 0){
                    pthread_cond_wait(&waiter, &lock2);
                    package->my_latest_lgprime = largest_prime;//largest_prime is global
                    update_ready = 0;
               }
               pthread_mutex_unlock(&lock2);
               if(num > (package->my_latest_lgprime+100)){
                    if(isPrime(num)==1){
                         *(package->fac_prime) = num;
                         package->my_latest_lgprime = num;
                         pthread_mutex_lock(&lock);
                         update_check = 1;
                         pthread_mutex_unlock(&lock);
                         pthread_cond_signal(&updater);  
                    }

               }
               count--;
          }
     }

     done++;
     return (void*)package;
}`

Фасилитатор:

void* facilitator(void* args){
     int i, temp_large;
     f_pack* package = (f_pack*) args;

     while(done != package->threads){
          pthread_mutex_lock(&lock);
          while(update_check == 0)
               pthread_cond_wait(&updater, &lock);
          temp_large = isLargest(package->threads_largest, package->threads);
          if(temp_large > largest_prime){
               pthread_mutex_lock(&lock2);
               update_ready = 1;
               largest_prime = temp_large;
               pthread_mutex_unlock(&lock2);
               pthread_cond_broadcast(&waiter);
               printf("New large prime: %d\n", largest_prime);
          }
          update_check = 0;
          pthread_mutex_unlock(&lock);
     }
}

Вот рабочий пакет

typedef struct worker_package{
     int my_latest_lgprime;
     int file_count;
     int* fac_prime;
     FILE* assigned_files[5];
} w_pack;

Есть ли более простой способ сделать это с помощью семафоров?

1 Ответ

1 голос
/ 10 декабря 2011

Я не могу точно определить проблему с уверенностью, но просто кратко прочитав код, кажется, что переменная done является общей для всех потоков, но к ней можно обращаться и изменять без синхронизации.

В любом случаеЯ могу предложить несколько идей по улучшению вашего решения.

  1. Вы назначаете список файлов каждому потоку при запуске.Это не самый эффективный способ, поскольку обработка каждого файла может занять больше или меньше времени.Мне кажется, что лучшим подходом было бы иметь один список файлов, а затем каждый поток выбирает следующий файл в списке.

  2. Вам действительно нужна задача посредника дляэтот?Мне кажется, что каждый поток может отслеживать свое наибольшее простое число, и каждый раз, когда он находит новый максимум, он может проверять глобальный максимум и обновлять его при необходимости.Вы также можете сохранить один максимум (без максимума на поток), но это потребует блокировки каждый раз, когда вам нужно сравнить.

Вот псевдокод того, как янаписал бы рабочие потоки:

while (true) {
    lock(file_list_mutex)
    if file list is empty {
        break // we are done!
    }
    file = get_next_file_in_list
    unlock(file_list_mutex)

    max = 0
    foreach number in file {
        if number is prime and number > max {
            lock(max_number_mutex)
            if (number > max_global_number) {
                max_global_number = number
            }
            max = max_global_number
            unlock(max_number_mutex)
        }
    }
}

Перед тем, как запускать рабочие потоки, вам нужно инициализировать max_global_number = 0.

Преимущество вышеупомянутого решения состоит в том, что оно не использует блокировки, какваш случай, так что конфликт нитей сведен к минимуму.

...