Я адаптировал очень хороший omp-распараллеленный код для выполнения числовой интеграции, которую я нашел здесь . Тем не менее, некоторые профилирования массива показали, что происходит серьезная утечка памяти ... Я думаю, это связано с тем, как происходит выталкивание элементов из стека, когда верхний элемент в стеке возвращается, но не удаляется из стека.
Итак, я решил, что могу легко добавить эту отсутствующую функцию, как я делал это раньше в последовательном коде. Но я явно делаю что-то не так, потому что я получаю «ошибку неверного указателя» после нескольких «освобождений» ...
Поскольку я совершенно новичок в OMP, я решил спросить вас ребята за помощь. Мне очень жаль, что я не смог больше справиться со своим «примером». Но я думаю, что важно увидеть, как автор реализовал связанный список и какие структуры данных.
Я думаю, что большая часть кода ниже может быть пропущена, мне кажется, это нормально. Проблема возникает, когда я пытаюсь «освободить» данные, связанные с верхним элементом стека, в функции «pop_stack» в самом конце.
Кажется, что добавление элементов в последовательный порт работает нормально - внутри параллельной секции это не так. Можете ли вы определить ошибку (ы)?
Примечание. Это неполный код. Он не скомпилируется.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#include <math.h>
int num_threads;
#define INITIAL_STACK_SIZE 128
/* the stack structure */
struct stack_s{
int el_count; /* count of elements on stack */
int el_size; /* size of an element */
int mem_reserve; /* allocated memory for stack */
void* elements; /* pointer to begin of stack */
};
struct myparams { double c1; double c1;};
typedef struct _work_t{
double a;
double b;
double rec; /* max recursion depth */
struct myparams * p;
} work_t;
typedef struct stack_s* stack_t;
void create_stack(stack_t* stack, int element_size);
int empty_stack(stack_t stack);
void push_stack(stack_t stack, void* element);
void pop_stack(stack_t stack, void* element);
double do_something(
double (*f)(double,struct myparams*), /* function to be called */
double a,
double b,
int rec, /*max. recursion depth*/
struct myparams* p);
static double myfun(double x,struct myparams* p){ return exp(-x*x)/p->a+log(x*pow(p->b,2.0));}
int main(int argc,char** argv)
{
num_threads=omp_get_num_threads();
double a=somevalue;
double b=somevalue;
struct myparams pinit;
pinit.c1=someval;
pinit.c2=someval;
double answer=0;
#pragma omp parallel
{
answer = do_something(myfun, xmin, xmax, 100, &pinit);
} /* omp parallel */
return 0;
}
double do_something(
double (*f)(double,struct myparams*), /* function to be called */
double a,
double b,
int rec,
struct myparams* p)
{
stack_t stack;
work_t work;
int ready, idle, busy;
/* prepare stack */
work.a = a;
work.b = b;
work.rec=rec;
work.p=p;
create_stack(&stack, sizeof(work_t));
push_stack(stack, &work);
double result = 0.0;
busy = 0;
#pragma omp parallel default(none) \
shared(stack, result,f,busy) \
private(work, idle, ready)
{
ready = 0;
idle = 1;
while(!ready )
{
#pragma omp critical (stack)
{
if (!empty_stack(stack)){
/* we have new work */
pop_stack(stack, &work);
if (idle){
/* say others i'm busy */
busy += 1;
idle = 0;
}
}else{
/* no new work on stack */
if (!idle){
busy -= 1;
idle = 1;
}
/* nobody has anything to do; let us leave the loop */
if (busy == 0)
ready = 1;
}
} /* end critical(stack) */
if (idle)
continue;
/* do some calculations using values saved in work and as well as the function f
along with the function parameters saved in myparams
-> estimate an error & save it to 'delta' */
if(rec <= 0 || fabs(delta) <= global_tolerance)
{
//error acceptable
#pragma omp critical (result)
result += somevalue_computed_above;
}
else // error not acceptable
{
//push 2 new work-elements to stack
//prepare 1st new elem.
work.a = some_new_a;
work.b = some_new_b;
work.rec=rec-1;
#pragma omp critical (stack)
{
push_stack(stack, &work);
//prepare 2nd new element
work.a = some_new_a2;
work.b = some_new_b2;
work.rec=rec-1;
push_stack(stack, &work);
}
}
} /* while */
} /* end omp parallel */
return result;
}
/******************************************
* create new stack
******************************************/
void
create_stack(
stack_t* stack, /* stack to create */
int element_size) /* size of a stack element */
{
int initial_size = INITIAL_STACK_SIZE;
/* allocate memory for new stack struct */
(*stack) = (stack_t) malloc(sizeof(struct stack_s));
if (!(*stack)){
fprintf(stderr, "error: could not allocate memory for stack.. Abort.\n");
exit(1);
}
/* allocate memory for stack elements */
(*stack)->elements = (void*) malloc(element_size * initial_size);
(*stack)->mem_reserve = initial_size;
if (!(*stack)->elements){
fprintf(stderr, "error: could not allocate memory for stack.. Abort.\n");
exit(1);
}
(*stack)->el_size = element_size;
(*stack)->el_count = 0;
}
/*****************************************
* check if the stack is empty
*****************************************/
int
empty_stack
(stack_t stack)
{
return stack->el_count <= 0;
}
/*****************************************
* push a element on stack
*****************************************/
void
push_stack(
stack_t stack, /* target stack */
void* element) /* element to push */
{
int i, new_reserve;
int log2_count;
/* check if we need more memory for stack */
if (stack->el_count >= stack->mem_reserve){
/* calculate new size for the stack
it should be a power of two */
for (i = stack->el_count, log2_count = 0;
i > 0;
i>>1, log2_count++);
new_reserve = 1 << log2_count;
/* reallocate memory for phase thread tables
and nullify new values */
stack->elements = (void *) realloc(stack->elements,
stack->el_size * new_reserve);
if (!stack->elements){
fprintf(stderr, "error: can't reallocate stack.. Aborting\n");
exit(1);
}
stack->mem_reserve = new_reserve;
}
/* now push the element on top of the stack */
memcpy((char*)stack->elements + stack->el_count*stack->el_size,
element, stack->el_size);
stack->el_count++;
}
/*****************************************
* pop an element from stack
* THIS IS WHERE I SUSPECT A MISTAKE !
*****************************************/
void pop_stack(
stack_t stack, /* target stack */
void* element) /* where poped el. should be stored */
{
if (stack->el_count <= 0){
fprintf(stderr, "error: trying to pop from empty stack.\n");
exit(2);
}
stack->el_count--;
memcpy(element,
(char*)stack->elements + stack->el_count*stack->el_size,
stack->el_size);
// try to remove last element from stack
// in original code there was no cleanup
struct _work_t *tmp = (struct _work_t*) stack->elements+stack->el_count;
printf("ncount:%d, foo:%f\n",stack->el_count+1,tmp->a);
free(tmp); //Works as long as el_count == 1 but fails if it becomes 2
}