pthread_create()によって呼び出される関数への複数の引数?


93

別のスレッドで呼び出したい関数に複数の引数を渡す必要があります。私がしまし読んこれを行うための典型的な方法は、構造体を定義することへの関数のポインタを渡し、引数のためにそれを逆参照することであること。ただし、これを機能させることはできません。

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

struct arg_struct {
    int arg1;
    int arg2;
};

void *print_the_arguments(void *arguments)
{
    struct arg_struct *args = (struct arg_struct *)args;
    printf("%d\n", args -> arg1);
    printf("%d\n", args -> arg2);
    pthread_exit(NULL);
    return NULL;
}

int main()
{
    pthread_t some_thread;
    struct arg_struct args;
    args.arg1 = 5;
    args.arg2 = 7;

    if (pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0) {
        printf("Uh-oh!\n");
        return -1;
    }

    return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}

この出力は次のようになります。

5
7

しかし、実行すると実際に次のようになります。

141921115
-1947974263

誰かが私が間違っていることを知っていますか?


2
ヒープに割り当ててみますか?
カーソンマイヤーズ

1
@カーソンなぜそれが違いを生むのか?
sigjuice 2009

5
構造は、少なくともスレッドと同じ長さでなければなりません。スレッドを作成し、pthread_create()を呼び出した関数から戻る場合、スタックに割り当てられた構造が他のデータによって上書きされ、スレッド関数で問題が発生する可能性があります。この例では、作成スレッドはワーカースレッドが完了するのを待ってから戻るため、問題ありません。
コモドールイエガー

@コモドールイエーガーああ!ありがとう、それは私が一緒に働いていた他の人との問題でした。Carsonが言ったように、malloc()を使用してヒープに割り当てることで修正しました。それは今ではもっと理にかなっています。
マイケル

回答:


77

あなたが言うから

struct arg_struct *args = (struct arg_struct *)args;

の代わりに

struct arg_struct *args = arguments;


4
@sigjuice、それは私にはうまくいきません。コンパイルエラーが表示されます。「void *」から「arg_struct *」への変換が無効です。
Neshta 2014年


4

main()独自のスレッド変数とスタック変数があります。ヒープの「args」にメモリを割り当てるか、グローバルにします。

struct arg_struct {
    int arg1;
    int arg2;
}args;

//declares args as global out of main()

その後、もちろん参照をargs->arg1からargs.arg1などに変更します。


2

使用する:

struct arg_struct *args = malloc(sizeof(struct arg_struct));

そして、この引数を次のように渡します:

pthread_create(&tr, NULL, print_the_arguments, (void *)args);

無料の引数を忘れないでください!;)


1

print_the_argumentsの引数は引数なので、以下を使用する必要があります。

struct arg_struct *args = (struct arg_struct *)arguments. 

1
struct arg_struct *args = (struct arg_struct *)args;

->この割り当ては間違っています。つまり、このコンテキストでは変数引数を使用する必要があります。乾杯!!!


1

このコードのスレッド作成では、関数ポインターのアドレスが渡されています。オリジナル pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0

それは次のように読みます pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

覚えておくと良いのは、この関数の引数はすべてアドレスでなければならないということです。

some_threadは静的に宣言されるため、アドレスはを使用して適切に送信されます&

pthread_attr_t変数を作成し、それを使用pthread_attr_init()して、その変数のアドレスを渡します。ただし、NULLポインタを渡すことも有効です。

&機能ラベルの前には、ここでの問題を引き起こしているものです。使用されるラベルはすでにvoid*関数に対するものであるため、ラベルのみが必要です。

!= 0最後の議論で言うことは、不確定な行動を引き起こすように思われるでしょう。これを追加すると、参照の代わりにブール値が渡されます。

Akash Agrawalの回答も、このコードの問題の解決策の一部です。


1

元のポスターのマイケルと同じ質問です。

しかし、私は成功せずに元のコードに提出された回答を適用しようとしました

試行錯誤を繰り返した結果、動作する(または少なくとも動作する)コードのバージョンを次に示します。よく見ると、以前に投稿されたソリューションとは異なることに気付くでしょう。

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

struct arg_struct
{
   int arg1;
   int arg2;
} *args;

void *print_the_arguments(void *arguments)
{
   struct arg_struct *args = arguments;
   printf("Thread\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   pthread_exit(NULL);
   return NULL;
}

int main()
{
   pthread_t some_thread;
   args = malloc(sizeof(struct arg_struct) * 1);

   args->arg1 = 5;
   args->arg2 = 7;

   printf("Before\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   printf("\n");


   if (pthread_create(&some_thread, NULL, &print_the_arguments, args) != 0)
   {
      printf("Uh-oh!\n");
      return -1;
   }

   return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.