0

bailey-borwein-plouffe式を使用して円周率の値を計算するプログラムを作成しています。私の問題は、ミューテックスを使用してこのコードを実行するたびに異なる結果が得られることです。パイ関数定義のミューテックスロックかどうかはわかりません。 1つのリソースpiにのみ使用する必要があります。

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);
  }



  }
4

2 に答える 2

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依存します。これで、 (ミューテックス内で)適切に制御されますが、パラメーターとして渡されるため、制御されません。kp16p16k

あなたが抱えている問題は、スレッドをで開始するk == 7前にスレッドを開始しk == 8ても、前者が最初にミューテックスを取得するという保証はないということです。後者が最初にミューテックスを取得する場合、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スレッドの実行順序に関係なく、ステップに保持されます。

ただし、この場合、スレッドは悪い考えであると私はまだ主張しています。

于 2013-01-30T02:26:49.117 に答える
1

の使用sが正しくありません。に適用されるパワーp16は一致する必要がありますが、ランダムに選択されたkのシーケンシャルパワーを使用しています。これは私が見つけた式によるものです。p16k

ランダムに選択される理由kは、スレッドが開始されると、スレッドの順序を制御できないためです。

したがって、この行:

int k = (int)s;

kスレッドに渡されたの値に設定します。ただし、どの値kに設定されるかは、スレッドが実行される順序によって異なります。

s == 0のスレッドが最初に移動する場合、およびのスレッドがs == n+1常に。のスレッドの後に移動する場合にのみ、正しい答えが得られますs == n

これが私の最後の編集です。スレッドを完全に破棄する以外のプログラムを修正する1つの方法は、各スレッドが回答の一部を計算するように合計を分離することです。正しい回答は、各スレッドの部分的な合計を合計することによって得られます。たとえば、4つのスレッドがあり、各スレッドはから始まり、i = { 0, 1, 2, 3 }それぞれが最初の項からオフセットされた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;
于 2013-01-30T02:20:19.690 に答える