web-dev-qa-db-ja.com

Cのpthreadスレッドから値を返す方法は?

私はCに慣れていないので、スレッドを少し試してみたいと思います。 pthread_exit()を使用してスレッドから値を返したい

私のコードは次のとおりです。

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

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;

   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   

   return 0;
}

プログラムは「42\n」を出力するはずですが、乱数が出力されます。返された値を印刷するにはどうすればよいですか?

編集:最初の回答によると、問題はローカル変数へのポインタを返しているということです。複数のスレッドの変数を返す/保存するベストプラクティスは何ですか?グローバルハッシュテーブル?

前もって感謝します

44
Petr Peller

スレッド関数の終了時に存在しないローカル変数のアドレスを返しています。いずれにせよ、なぜpthread_exitを呼び出すのですか?スレッド関数から単純に値を返さないのはなぜですか?

void *myThread()
{
   return (void *) 42;
}

そして、メインで:

printf("%d\n",(int)status);   

このような構造のような複雑な値を返す必要がある場合、malloc()を使用して動的に割り当ててポインタを返すのがおそらく最も簡単です。もちろん、スレッドを開始したコードがメモリを解放します。

43
anon

ローカル変数へのポインターを返しました。スレッドが関与していなくても、それは悪いことです。

これを行う通常の方法は、開始するスレッドが結合するスレッドと同じ場合、pthread_createの4番目のパラメーターとして、呼び出し元が管理する場所にあるintにポインターを渡すことです。これは、スレッドのエントリポイントへの(唯一の)パラメータになります。 (必要に応じて)スレッド終了値を使用して成功を示すことができます。

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

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}

構造体のスレッド終了値を絶対に使用する必要がある場合は、動的に割り当てる必要があります(そして、スレッドに参加する人がそれを解放することを確認してください)。しかし、それは理想的ではありません。

26
Steve Jessop

これが正しい解決策です。この場合、tdataはメインスレッドに割り当てられ、スレッドが結果を配置するためのスペースがあります。

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

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}
21
salsaman

数値をヒープに格納する必要があると思います。 int ret変数はスタック上にあり、関数myThreadの実行の終了時に破壊されました。

void *myThread()
{
       int *ret = malloc(sizeof(int));
       if (ret == NULL) {
           // ...
       }
       *ret = 42;
       pthread_exit(ret);
}

必要ないときはfreeすることを忘れないでください:)

別の解決策は、Neil Butterworthが示唆するように、ポインターの値として数値を返すことです。

4
Messa
#include<stdio.h>
#include<pthread.h>
void* myprint(void *x)
{
 int k = *((int *)x);
 printf("\n Thread created.. value of k [%d]\n",k);
 //k =11;
 pthread_exit((void *)k);

}
int main()
{
 pthread_t th1;
 int x =5;
 int *y;
 pthread_create(&th1,NULL,myprint,(void*)&x);
 pthread_join(th1,(void*)&y);
 printf("\n Exit value is [%d]\n",y);
}  
2
Abhishek

スタック上の変数であるretへの参照を返しています。

2
Maurits Rijk

質問:複数のスレッドの変数を返す/格納するベストプラクティスは何ですか?グローバルハッシュテーブル?

これは、何を返したいのか、どのように使用するのかによってまったく異なりますか?スレッドの状態(スレッドが意図したことを完了したかどうかなど)のみを返す場合は、pthread_exitを使用するか、returnステートメントを使用してスレッド関数から値を返します。

しかし、さらに処理するために使用される情報がさらに必要な場合は、グローバルデータ構造を使用できます。ただし、その場合は、適切な同期プリミティブを使用して同時実行の問題を処理する必要があります。または、(おそらくデータを格納する構造に)動的メモリを割り当ててpthread_exit経由で送信し、スレッドが結合したら、別のグローバル構造で更新できます。この方法では、1つのメインスレッドのみがグローバル構造を更新し、同時実行の問題が解決されます。ただし、異なるスレッドによって割り当てられたすべてのメモリを必ず解放する必要があります。

1
Jay

アドレスを返すことに不安があり、変数が1つしかない場合など。返す整数値は、渡す前に(void *)に型キャストすることもできます。その後、メインでそれを収集するときに、再び(int)に型キャストします。い警告を出さずに価値があります。

0
Aditya