2015-06-09 6 views
0

Работала над этим заданием для класса. Поместите этот код вместе, но он дает мне несколько ошибок, которые я не могу решить.Unix c программа для вычисления pi с помощью потоков

Код

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

//global variables 
int N, T; 
double vsum[T]; 

//pie function 
void* pie_runner(void* arg) 
{ 
    double *limit_ptr = (double*) arg; 
    double j = *limit_ptr; 

    for(int i = (N/T)*j; i<=((N/T)*(j+1)-1); j++) 
    { 
     if(i %2 =0) 
      vsum[j] += 4/((2*j)*(2*j+1)*(2*j+2)); 
     else 
      vsum[j] -= 4/((2*j)*(2*j+1)*(2*j+2)); 

    } 

    pthread_exit(0); 
} 

int main(int argc, char **argv) 
{ 

    if(argc != 3) { 
     printf("Error: Must send it 2 parameters, you sent %s", argc); 
     exit(1); 
    } 
    N = atoi[1]; 
    T = atoi[2]; 

    if(N !> T) { 
     printf("Error: Number of terms must be greater then number of threads."); 
     exit(1);  
    } 

    for(int p=0; p<T; p++)  //initialize array to 0 
    { 
     vsum[p] = 0; 
    } 

    double pie = 3; 
    //launch threads 
    pthread_t tids[T]; 

    for(int i = 0; i<T; i++) 
    { 
     pthread_attr_t attr; 
     pthread_attr_init(&attr); 
     pthread_create(&tids[i], &attr, pie_runner, &i); 
    } 

    //wait for threads... 
    for(int k = 0; k<T; k++) 
    { 
     pthread_join(tids[k], NULL); 
    } 

    for(int x=0; x<T; x++) 
    { 
     pie += vsum[x]; 
    } 

    printf("pi computed with %d terms in %s threads is %k\n", N, T, pie); 


} 

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

Любая помощь приветствуется, а также остальная часть кода.

** EDIT: после обновления кода, используя приведенные ниже комментарии, вот новый код. У меня осталось еще несколько ошибок, и мне было бы полезно помочь им. 1) Предупреждение: литье из указателя в целое число разного размера [-Wpointer-to-int-cast] int j = (int) arg; 2) Предупреждение: приведение к указателю из целого разного размера [Wint to to-pointer - cast] pthread_create (.........., (void *) i);

НОВЫЙ КОД:

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

//global variables 
int N, T; 
double *vsum; 

//pie function 
void* pie_runner(void* arg) 
{ 
    long j = (long)arg;  
    //double *limit_ptr = (double*) arg; 
    //double j = *limit_ptr; 

    //for(int i = (j-1)*N/T; i < N*(j) /T; i++) 
    for(int i = (N/T)*(j-1); i < ((N/T)*(j)); i++) 
    { 

     if(i % 2 == 0){ 
      vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2)); 
      //printf("vsum %lu = %f\n", j, vsum[j]); 
        } 
     else{ 
      vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2)); 
      //printf("vsum %lu = %f\n", j, vsum[j]); 
        } 


    } 

    pthread_exit(0); 
} 

int main(int argc, char **argv) 
{ 

    if(argc != 3) { 
     printf("Error: Must send it 2 parameters, you sent %d\n", argc-1); 
     exit(1); 
    } 
    N = atoi(argv[1]); 
    T = atoi(argv[2]); 

    vsum = malloc((T+1) * sizeof(*vsum)); 
    if(vsum == NULL) { 
     fprintf(stderr, "Memory allocation problem\n"); 
     exit(1); 
    } 

    if(N <= T) { 
     printf("Error: Number of terms must be greater then number of threads.\n"); 
     exit(1);  
    } 

    for(int p=1; p<=T; p++)  //initialize array to 0 
    { 
     vsum[p] = 0; 
    } 

    double pie = 3.0; 
    //launch threads 
    pthread_t tids[T+1]; 

    for(long i = 1; i<=T; i++) 
    { 
     pthread_attr_t attr; 
     pthread_attr_init(&attr); 
     pthread_create(&tids[i], &attr, pie_runner, (void*)i); 
    } 

    //wait for threads... 
    for(int k = 1; k<=T; k++) 
    { 
     pthread_join(tids[k], NULL); 
    } 

    for(int x=1; x<=T; x++) 
    { 
     pie += vsum[x]; 
    } 

    printf("pi computed with %d terms in %d threads is %.20f\n", N, T, pie); 

    //printf("pi computed with %d terms in %d threads is %20f\n", N, T, pie); 

    free(vsum); 
} 

Значение не работает:

./pie1 2 1 
pi computed with 2 terms in 1 threads is 3.00000000000000000000 
./pie1 3 1 
pi computed with 3 terms in 1 threads is 3.16666666666666651864 
./pie1 3 2 
pi computed with 3 terms in 2 threads is 3.13333333333333330373 
./pie1 4 2 
pi computed with 4 terms in 2 threads is 3.00000000000000000000 
./pie1 4 1 
pi computed with 4 terms in 1 threads is 3.00000000000000000000 
./pie1 4 3 
pi computed with 4 terms in 3 threads is 3.14523809523809516620 
./pie1 10 1 
pi computed with 10 terms in 1 threads is 3.00000000000000000000 
./pie1 10 2 
pi computed with 10 terms in 2 threads is 3.13333333333333330373 
./pie1 10 3 
pi computed with 10 terms in 3 threads is 3.14523809523809516620 
./pie1 10 4 
pi computed with 10 terms in 4 threads is 3.00000000000000000000 
./pie1 10 5 
pi computed with 10 terms in 5 threads is 3.00000000000000000000 
./pie1 10 6 
pi computed with 10 terms in 6 threads is 3.14088134088134074418 
./pie1 10 7 
pi computed with 10 terms in 7 threads is 3.14207181707181693042 
./pie1 10 8 
pi computed with 10 terms in 8 threads is 3.14125482360776464574 
./pie1 10 9 
pi computed with 10 terms in 9 threads is 3.14183961892940200045 
./pie1 11 2 
pi computed with 11 terms in 2 threads is 3.13333333333333330373 
./pie1 11 4 
pi computed with 11 terms in 4 threads is 3.00000000000000000000 
+3

* "но он продолжает говорить мне, что это не константа" * - если это сообщение о компиляторе или сообщение об ошибке, отправьте точное текс t и отметьте линию, в которой она находится. –

+1

C и C++ имеют общее наследие, но они не являются одним и тем же языком. Поскольку в исходном коде нет ни малейшего бита C++, и вы явно указываете C в заголовке, я удалил тег C++. – paxdiablo

ответ

2

Существует множество проблем с этим кодом. Ваша конкретная проблема заключается в том, что в C массивы с переменной длиной (VLA) не разрешены в области файлов.

Так что, если вы хотите, чтобы массив быть динамичным, вы должны объявить указатель на него и выделить его самостоятельно:

int N, T; 
double *vsum; 

, а затем, в main() после T было установлено:

vsum = malloc (T * sizeof(*vsum)); 
if (vsum == NULL) { 
    fprintf (stderr, "Memory allocation problem\n"); 
    exit (1); 
} 

вспомнить, чтобы освободить его перед выходом (технически не требуется, но в любом случае хорошая форма):

free (vsum); 

Среди других проблем:


1/Там нет !> оператора в C, я подозреваю, что линия должна быть:

if (N > T) { 

вместо:

if (N !> T) { 

2/Чтобы получить аргументы из командной строки, измените:

N = atoi[1]; 
T = atoi[2]; 

в:

N = atoi(argv[1]); 
T = atoi(argv[2]); 

3/Оператор сравнения ==, не =, так что вам нужно изменить:

if(i %2 =0) 

в:

if (i % 2 == 0) 

4/Ваше сообщение об ошибке о не достаточно параметров необходимо использовать %d, а не %s, поскольку argc является интегральный тип:

printf ("Error: Must send it 2 parameters, you sent %d\n", argc-1); 

Ditto для расчета сообщения в конце (и фиксации %k для значения с плавающей запятой):

printf ("pi computed with %d terms in %d threads is %.20f\n", N, T, pie); 

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

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

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

Чтобы исправить и те, использовать это при создании нити:

pthread_create (&tids[i], &attr, pie_runner, (void*)i); 

и это в начале функции потока:

int j = (int) arg; 

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

pthread_create (&tids[i], &attr, pie_runner, (void*)(intptr_t)i); 

, хотя я не уверен, что будет работать лучше.

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

Во-первых, восстановить функцию нити для получения его значения по указателю:

int j = *((int*) arg); 

Затем, прежде чем начать создавать темы, необходимо создать поток целых чисел, и для каждого потока создания, заполнения и передать (адрес) правильный индекс этого массива:

int tvals[T];     // add this line. 
for (int i = 0; i < T; i++) { 
    tvals[i] = i;    // and this one. 
    pthread_attr_t attr; 
    pthread_attr_init (&attr); 
    pthread_create (&tids[i], &attr, pie_runner, &(tvals[i])); 
} 

Это не должно быть слишком обременительным, если у вас так много потоков массив эстра будет проблематично. Но, если у вас есть , что много потоков, у вас будут гораздо большие проблемы.


6/Ваш цикл в потоке неправильно увеличивается j, а не i. Поскольку это тот же самый участок, затронутый в следующем разделе, я исправлю его там.


7/Использование целых чисел в том, что в основном расчет с плавающей точкой означает, что вы должны организовать свои расчеты так, чтобы они не усечь подразделения, такие как 10/4 -> 2 where it should be 2.5.

Это означает, что цикл в функции потока должен быть изменен следующим образом (в том числе увеличивающихся i, как и в предыдущем пункте):

for (int i = j*N/T; i <= N * (j+1)/T - 1; i++) 
    if(i % 2 == 0) 
     vsum[j] += 4.0/((2*j)*(2*j+1)*(2*j+2)); 
    else 
     vsum[j] -= 4.0/((2*j)*(2*j+1)*(2*j+2)); 

С все этих изменениями, вы получите достаточно разумный результат :

$ ./picalc 100 101 
pi computed with 100 terms in 101 threads is 3.14159241097198238535 
+0

Прежде всего, спасибо большое. Но у меня все еще есть какие-то удары, на которые я застрял. Для начала он не будет компилироваться, потому что я объявил переменные в цикле, поэтому мне пришлось добавить -std = c99.Сделав это и сделав все изменения, которые вы предложили, у меня все еще были ошибки. 1) Предупреждение: литье из указателя в целое число разного размера [-Wpointer-to-int-cast] int j = (int) arg; 2) Предупреждение: приведение к указателю из целого разного размера [Wint to to-pointer - cast] pthread_create (.........., (void *) i); .. Ошибки кажутся как в изменении, внесенном в ваш комментарий к разделу 5. Любые предложения? – user1927242

+0

@ user1927242, это _warnings_, а не ошибки, поэтому, предполагая, что 'void *' может фактически содержать 'int', должно быть все в порядке. Попробуйте запустить его и посмотреть, получите ли вы правильные результаты. Он не может быть переносимым, например, если реализация имеет 64-битные int, но 32-разрядные указатели, но это вряд ли возможно. Если это реальная проблема, есть и другие пути, такие как передача адреса int в массиве типа 'int ints [] = {0,1,2,3, ..., T-1};' но я бы попробовал то, что у вас есть в первую очередь. Я добавлю этот метод когда-нибудь сегодня. – paxdiablo

+0

Он не будет работать с этими предупреждениями по какой-то причине – user1927242

2

Две проблемы с этим массивом: Первое, что T не время компиляции постоянная, она должна если вы программируете на C++. Во-вторых, T инициализируется до нуля, то есть массив будет иметь нулевой размер, и вся индексация массива будет за пределами границ.

Вам необходимо выделить массив динамически после того, как вы прочитали T и знаете размер. В C вы используете malloc для этого, на C++ вместо этого вы должны использовать std::vector.