Аводирование многопоточных порождений в pthreads - PullRequest
0 голосов
/ 24 мая 2010

У меня есть приложение, которое распараллелено с использованием pthreads. Приложение имеет итеративный вызов подпрограммы и порождает поток в рутину (pthread_create и pthread_join), чтобы распараллелить интенсивный раздел вычислений в подпрограмме Когда я использую инструментальные средства, такие как ПИН, для сбора статистики, инструмент сообщает статистику по нескольким потокам (нет потоков, нет итераций). Я полагаю, это потому, что он порождает новый набор потоков каждый раз, когда вызывается подпрограмма.

  1. Как я могу гарантировать, что я создаю поток только один раз, и все последующие вызовы используют потоки, которые были созданы первыми.

  2. Когда я делаю то же самое с OpenMP, а затем пытаюсь собрать статистику, я вижу, что потоки создаются только один раз. Это из-за времени выполнения OpenMP?

EDIT:

я даю упрощенную версию кода.

int main() 
{ 
  //some code 
  do { 
    compute_distance(objects,clusters, &delta); //routine with pthread 
  } while (delta > threshold ) 
}
void compute_distance(double **objects,double *clusters, double *delta) 
{ 
   //some code again 
   //computation moved to a separate parallel routine.. 
   for (i=0, i<nthreads;i++) 
     pthread_create(&thread[i],&attr,parallel_compute_phase,(void*)&ip); 
   for (i=0, i<nthreads;i++) 
     rc = pthread_join(thread[i], &status); 
} 

Надеюсь, это ясно объясняет проблему.

  1. Как сохранить идентификатор потока и проверить, был ли он уже создан?

Ответы [ 3 ]

0 голосов
/ 25 мая 2010

Легкая вещь, которую вы можете сделать с минимальными изменениями кода, - это написать несколько оболочек для pthread_create и _join. В основном вы можете сделать что-то вроде:

typedef struct {
  volatile int go;
  volatile int done;
  pthread_t h;
  void* (*fn)(void*);
  void* args;
} pthread_w_t;

void* pthread_w_fn(void* args) {
    pthread_w_t* p = (pthread_w_t*)args;
    // just let the thread be killed at the end
    for(;;) {
        while (!p->go) { pthread_yield(); };  // yields are good
        p->go = 0;  // don't want to go again until told to
        p->fn(p->args);
        p->done = 1;
    }
}

int pthread_create_w(pthread_w_t* th, pthread_attr_t* a,
                     void* (*fn)(void*), void* args) {
    if (!th->h) {
        th->done = 0;
        th->go = 0;
        th->fn = fn;
        th->args = args;
        pthread_create(&th->h,a,pthread_w_fn,th);
    }
    th->done = 0; //make sure join won't return too soon
    th->go = 1;   //and let the wrapper function start the real thread code
}

int pthread_join_w(pthread_w_t*th) {
  while (!th->done) { pthread_yield(); };
}

, а затем вам придется изменить свои вызовы и pthread_ts или создать несколько макросов #define, чтобы изменить pthread_create на pthread_create_w и т. Д. .... и вам придется инициализировать ваш pthread_w_ts в ноль.

Однако возиться с этими летучими веществами может быть хлопотно. вам, вероятно, придется потратить некоторое время на то, чтобы мои грубые наброски действительно работали должным образом.

0 голосов
/ 30 мая 2010

Чтобы убедиться, что несколько потоков могут попытаться выполнить это только один раз, используйте pthread_once(). Чтобы гарантировать, что что-то случится только один раз, что может быть сделано одним потоком, просто используйте bool (вероятно, в статическом хранилище).

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

0 голосов
/ 24 мая 2010

Вы можете создать простую реализацию пула потоков, которая создает потоки и заставляет их спать.Когда требуется поток, вместо «pthread_create» вы можете попросить подсистему пула потоков выбрать поток и выполнить необходимую работу. Это обеспечит ваш контроль над числом потоков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...