私はあなたのコードを実行しようとしましたが、いくつかの驚きに遭遇しました:
printf("The number is: %d\n", finalFib);
この行には小さなエラーがあります。%d
つまり、がprintf
期待されますint
が、が渡されlong int
ます。ほとんどのプラットフォームでは、これは同じであるか、とにかく同じ動作をしますが、慎重に言えば(または、警告が表示されないようにしたい場合は、非常に高貴な理想です)、%ld
代わりに使用する必要があります。 long int
。_
fib
一方、あなたの機能は機能していないようです。私のマシンでテストすると、クラッシュしませんが1047
、フィボナッチ数ではないが得られます。よく見ると、プログラムはいくつかの点で正しくないようです。
void *fib(void *fibToFind)
{
long retval; // retval is never used
long newFibToFind = ((long)fibToFind);
long returnMinusOne; // variable is read but never initialized
long returnMinustwo; // variable is read but never initialized
pthread_t minusone; // variable is never used (?)
pthread_t minustwo; // variable is never used
if(newFibToFind == 0 || newFibToFind == 1)
// you miss a cast here (but you really shouldn't do it this way)
return newFibToFind;
else{
long newFibToFind1 = ((long)fibToFind) - 1; // variable is never used
long newFibToFind2 = ((long)fibToFind) - 2; // variable is never used
// reading undefined variables (and missing a cast)
return returnMinusOne + returnMinustwo;
}
}
コンパイラの警告には常に注意してください。警告を受け取ったとき、通常、あなたは本当に何か怪しいことをしています。
アルゴリズムを少し修正する必要があるかもしれません。現在、関数が行うのは2つの未定義の値の合計を返すことだけなので、以前に取得した1047です。
再帰的アルゴリズムを使用してフィボナッチスイートを実装すると、関数を再度呼び出す必要があります。他の人が指摘したように、それは非常に非効率的な方法ですが、簡単なので、すべてのコンピュータサイエンスの教師が例としてそれを使用していると思います。
通常の再帰的アルゴリズムは次のようになります。
int fibonacci(int iteration)
{
if (iteration == 0 || iteration == 1)
return 1;
return fibonacci(iteration - 1) + fibonacci(iteration - 2);
}
スレッドをどの程度使用することになっていたのかわかりません。セカンダリスレッドでアルゴリズムを実行するか、呼び出しごとに新しいスレッドを作成しますか?それははるかに簡単なので、今のところ最初のものを想定しましょう。
整数をポインタにキャストしたり、その逆を行ったりすることは悪い習慣です。より高いレベルで物事を見ようとすると、それらは大きく異なるはずだからです。整数は数学を行い、ポインタはメモリアドレスを解決します。それらが同じように表現されているため、たまたま機能しますが、実際には、これを行うべきではありません。代わりに、新しいスレッドを実行するために呼び出された関数が引数を受け入れることに気付くかもしれません。これを使用して、入力の場所と出力の場所void*
の両方を伝えることができます。
したがって、以前のfibonacci
関数に基づいて、このコードをスレッドのメインルーチンとして使用できます。
void* fibonacci_offshored(void* pointer)
{
int* pointer_to_number = pointer;
int input = *pointer_to_number;
*pointer_to_number = fibonacci(input);
return NULL;
}
整数へのポインタを期待し、そこから入力を受け取り、そこに出力を書き込みます。1次に、次のようなスレッドを作成します。
int main()
{
int value = 15;
pthread_t thread;
// on input, value should contain the number of iterations;
// after the end of the function, it will contain the result of
// the fibonacci function
int result = pthread_create(&thread, NULL, fibonacci_offshored, &value);
// error checking is important! try to crash gracefully at the very least
if (result != 0)
{
perror("pthread_create");
return 1;
}
if (pthread_join(thread, NULL)
{
perror("pthread_join");
return 1;
}
// now, value contains the output of the fibonacci function
// (note that value is an int, so just %d is fine)
printf("The value is %d\n", value);
return 0;
}
新しい個別のスレッドからフィボナッチ関数を呼び出す必要がある場合(注意:これは私がアドバイスすることではなく、他の人も私に同意しているようです。十分な量の反復で爆発するだけです)、最初にfibonacci
関数を関数とマージする必要がありfibonacci_offshored
ます。スレッドの処理は通常の関数の処理よりも重いため、かなり大きくなります。
void* threaded_fibonacci(void* pointer)
{
int* pointer_to_number = pointer;
int input = *pointer_to_number;
if (input == 0 || input == 1)
{
*pointer_to_number = 1;
return NULL;
}
// we need one argument per thread
int minus_one_number = input - 1;
int minus_two_number = input - 2;
pthread_t minus_one;
pthread_t minus_two;
// don't forget to check! especially that in a recursive function where the
// recursion set actually grows instead of shrinking, you're bound to fail
// at some point
if (pthread_create(&minus_one, NULL, threaded_fibonacci, &minus_one_number) != 0)
{
perror("pthread_create");
*pointer_to_number = 0;
return NULL;
}
if (pthread_create(&minus_two, NULL, threaded_fibonacci, &minus_two_number) != 0)
{
perror("pthread_create");
*pointer_to_number = 0;
return NULL;
}
if (pthread_join(minus_one, NULL) != 0)
{
perror("pthread_join");
*pointer_to_number = 0;
return NULL;
}
if (pthread_join(minus_two, NULL) != 0)
{
perror("pthread_join");
*pointer_to_number = 0;
return NULL;
}
*pointer_to_number = minus_one_number + minus_two_number;
return NULL;
}
このかさばる関数ができたので、main
関数の調整は非常に簡単になります。参照をfibonacci_offshored
に変更するだけthreaded_fibonacci
です。
int main()
{
int value = 15;
pthread_t thread;
int result = pthread_create(&thread, NULL, threaded_fibonacci, &value);
if (result != 0)
{
perror("pthread_create");
return 1;
}
pthread_join(thread, NULL);
printf("The value is %d\n", value);
return 0;
}
スレッドは並列プロセスを高速化すると言われたかもしれませんが、スレッドの内容を実行するよりもスレッドをセットアップする方がコストがかかるところには限界があります。これは、このような状況の非常に良い例です。スレッド化されたバージョンのプログラムは、スレッド化されていないバージョンよりもはるかに低速で実行されます。
教育目的で、このプログラムは、必要な反復回数が18のときに私のマシンのスレッドを使い果たし、実行に数秒かかります。比較すると、反復実装を使用すると、スレッドが不足することはなく、数ミリ秒で答えが得られます。また、かなり簡単です。これは、より優れたアルゴリズムを使用して多くの問題を解決する方法の良い例です。
また、好奇心から、それがあなたのマシンでクラッシュするかどうか、そしてどこで/どのようにクラッシュするかを見るのは興味深いでしょう。
1.通常、変数の意味を入力時の値と関数の戻り後の値の間で変更しないようにする必要があります。たとえば、ここでは、入力時に、変数は必要な反復回数です。出力では、それは関数の結果です。これらは2つの非常に異なる意味であり、それは実際には良い習慣ではありません。動的割り当てを使用して戻り値を介して値を返すことは気が進まなかったvoid*
。