2013-01-30 2 views
0

나는 bailey-borwein-plouffe 공식을 사용하여 pi의 값을 계산하는 프로그램을 작성하고 있습니다. 내 문제는 뮤텍스를 사용하여이 코드를 실행할 때마다 계속 다른 결과를 얻고 있습니다. 파이 함수 정의의 뮤텍스 잠금이 하나의 리소스 pi에만 사용되어야하는지 확실하지 않습니다.mutex를 사용하여이 프로그램을 동시에 실행할 때마다 다른 결과가 발생합니다.

enter code here 
#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <time.h> 
#define NUM_THREADS  1000 

void *pie_function(void * p);//returns the value of pie 
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; //creates a mutex variable 
double pi=0,p16=1; 
main() 
{ 
pthread_t threads[NUM_THREADS]; //creates the number of threads using NUM_THREADS 
int iret1; //used to ensure that threads are created properly 
     //pthread_create(thread,attr,start_routine,arg) 

int i; 
    pthread_mutex_init(&mutex1, NULL); 


for(i=0;i<NUM_THREADS;i++){ 
     iret1= pthread_create(&threads[i],NULL,pie_function,(void *) i); 
    if(iret1){ 
     printf("ERROR; return code from pthread_create() is %d\n", iret1); 
     exit(-1); 
    } 

} 

for(i=0;i<NUM_THREADS;i++){ 
    iret1=pthread_join(threads[i],NULL); 

if(iret1){ 
     printf("ERROR; return code from pthread_create() is %d\n", iret1); 
     exit(-1); 
    } 

}

pthread_mutex_destroy(&mutex1); 
    printf("Main: program completed. Exiting.\n"); 
    printf("The value of pi is : %f\n",pi); 

    exit(0); 

    } 



void *pie_function(void *s){ 
int rc; 
int k=(int) s; 
    pthread_mutex_lock(&mutex1); //locks the share variable pi and p16 
    pi += 1.0/p16 * (4.0/(8*k + 1) - 2.0/(8*k + 4) - 1.0/(8*k + 5) - 1.0/(8*k+6)); 
p16 *=16; 

rc=pthread_mutex_unlock(&mutex1); 
if(rc){ 
    printf("ERROR; return code from pthread_create() is %d\n", rc); 
    exit(-1); 
    } 



    } 

답변

2

당신은 완전히이 경우 스레드를 죽겠다 더 나을 것입니다.

스레딩은 스레드 그룹이 서로 영향을주지 않고 주로 작은 영역에서 실행할 수있는 경우에 편리합니다 (간혹 자원 경합은 정상입니다).

그러나 스레드가 매우 수명이 짧고 전체 수명 동안 뮤텍스를 잘 잠그기 때문에 스레딩에서 이점을 얻지 못합니다. 당신이하는 일은 거의 또는 전혀 이익을 위해 추가 오버 헤드를 추가하는 것뿐입니다.

이 작업은 일련의 순차적 인 단계로 처리하는 것이 좋습니다. 당신이 당신에게 해야이 일을 느낀다면


그러나, 다음과 같은 공식에보고하여 문제를 해결할 수 있습니다 : 분명히

pi += 1.0/p16 * (4.0/(8*k + 1) - 2.0/(8*k + 4) - 1.0/(8*k + 5) - 1.0/(8*k+6)); 

, pi에 추가됩니다 어떤 것은 모두 k에 따라 달라집니다 및 p16.이제 p16은 (뮤텍스 내에서) 잘 제어되지만 귀하의 k은 매개 변수로 전달 된 것이 아니기 때문입니다.

문제는 k == 8으로 시작하기 전에 k == 7으로 스레드를 시작할 수 있지만 이전에는 뮤텍스를 얻을 것이라는 보장이 없습니다. 후자가 뮤텍스를 먼저 얻으면 kp16은 "호환"값을 갖지 않습니다. 그러한 것은 스레딩의 모호함입니다.

k을 뮤텍스의 제어하에 배치하여이 문제를 해결할 수 있습니다.

다른 말로하면 매개 변수로 전달하지 말고 p16과 동일한 작업을 수행하십시오. 그들 모두를 초기화 :

double pi=0, p16=1; 
int k = 0; 

그런 다음 스레드 기능이이 포함되어

// Should actually check all mutex calls. 

pthread_mutex_lock (&mutex1); 
pi += 1.0/p16 * (4.0/(8*k + 1) - 2.0/(8*k + 4) - 1.0/(8*k + 5) - 1.0/(8*k+6)); 
p16 *=16; 
k++; 
pthread_mutex_unlock (&mutex1); 

이 방법은, kp16의 값은 스레드 실행 순서에 관계없이 단계에 보관됩니다.

그러나이 경우 스레드가 좋지 않습니다.

+1

절대적으로 맞습니다. 스레드를 사용하여 구현하고 싶습니다. 무엇을 잘못하고 있는지 확인하고 싶습니다. – user1850254

+0

@ user1850254, 당신이 잘못하고있는 것은 (쓰레딩이 필요하다면) 스레드가'k'의 순차적 인 값으로 작업을한다고 가정하고 있습니다 (user315052의 답 참조). 내 논쟁은 스레드가이 사용 사례에서 나쁜 생각이라는 것입니다. 스레딩을 배우고 싶다면 최소한 적절한 노력 영역을 선택하십시오 :-) – paxdiablo

+0

@ 파이 도움말을 계산하는 공식을 변경해야합니까? – user1850254

1

s의 사용이 잘못되었습니다. p16에 적용되는 전원은 k과 일치해야하지만 순차적으로 p16을 사용하여 임의로 k을 선택했습니다. 이것은 the formula에 의하면입니다.

k을 임의로 선택한 이유는 스레드가 시작된 후에 스레드의 순서를 제어 할 수 없기 때문입니다.

그래서이 라인 :

int k = (int)s; 

설정 스레드에 전달의 값 k. 그러나 k 값은 스레드가 실행되는 순서에 따라 달라집니다.

s == 0이있는 스레드가 먼저 도착하고 s == n+1 인 스레드가 항상 s == n 인 스레드를 따라 가면 올바른 대답을 얻을 수 있습니다.

이것은 마지막 편집입니다 : 스레드를 모두 버리는 것 이외의 프로그램을 수정하는 한 가지 방법은 합계를 분리하여 각 스레드가 응답의 일부를 계산하고 각각을 함께 추가하여 얻는 것입니다 thread의 부분 합계. 예를 들어, 각 스레드가 i = { 0, 1, 2, 3 }에서 시작하는 4 개의 스레드를 가질 수 있으며 각 스레드는 초기 기간의 4 번째 텀 오프셋의 합계를 계산합니다. 합계에 대한 정지 조건은 계산 된 항이 어떤 임계 값 아래로 떨어지는 경우입니다. 그래서, pie_function는 다음과 같이 구현 될 수있다 :

const double THRESH = 0.0000001; 
int k = (int)s; 
double p16 = pow(16, k); 
double p16_4 = pow(16, 4); 
double subpi = 0; 
for (;;) { 
    double k8 = 8*k; 
    double term = 1/p16 * (4/(k8+1) - 2/(k8+4) - 1/(k8+5) - 1/(k8+6)); 
    if (term < THRESH) break; 
    subpi += term; 
    k += 4; 
    p16 *= p16_4; 
} 
pthread_mutex_lock(&mutex1); 
pi += subpi; 
pthread_mutex_unlock(&mutex1); 
return 0; 
+0

나는 당신이 말한 것을 이해하지 못한다. K는 3.141591 t0 0.238109 – user1850254

+0

에서 int.my 값의 범위로 주조 된 s에서 얻은 내부 변수이다. 그러나 각 스레드가 자체 k에서 작동 할 것이므로 sum.eg에 4 개의 쓰레드가 있다면, 쓰레드 1은 3 번, 쓰레드 2는 1 번, 쓰레드 3 번은 4 번, 쓰레드 4는 3 번이 될 수있다. 총합을 얻고 있기 때문에 여전히 작동해야한다. – user1850254

+0

@ user1850254 : 수식이 잘못 적용됩니다. 2 개의 스레드를 가정합니다. 스레드가 이동하는 순서를 변경할 때 동일한 대답을 얻는 지 확인하십시오. – jxh

관련 문제