90

私が次のようなクラスを持っているとしましょう

class c { 
    // ...
    void *print(void *){ cout << "Hello"; }
}

そして、私はcのベクトルを持っています

vector<c> classes; pthread_t t1;
classes.push_back(c());
classes.push_back(c());

今、私はスレッドを作成したいc.print();

そして、以下は私に以下の問題を与えています:pthread_create(&t1, NULL, &c[0].print, NULL);

エラー出力:引数「3」の「void *(tree_item :: )(void)」を「void *()(void )」に変換できません」int pthread_create(pthread_t *、const pthread_attr_t *、void *( )(void)、void *)'</ p>

4

9 に答える 9

155

thisC++ クラス メンバ関数には隠しパラメータが渡され ているため、作成した方法では実行できません。使用するpthread_create()値がわからないthisため、メソッドを関数にキャストしてコンパイラを回避しようとすると適切なタイプのポインターを使用すると、セグメンテーション違反が発生します。クラスをブートストラップするには、静的クラス メソッド (パラメーターを持たないthis) またはプレーンな通常の関数を使用する必要があります。

class C
{
public:
    void *hello(void)
    {
        std::cout << "Hello, world!" << std::endl;
        return 0;
    }

    static void *hello_helper(void *context)
    {
        return ((C *)context)->hello();
    }
};
...
C c;
pthread_t t;
pthread_create(&t, NULL, &C::hello_helper, &c);
于 2009-07-20T03:52:39.250 に答える
85

スレッドを処理する私のお気に入りの方法は、スレッドを C++ オブジェクト内にカプセル化することです。次に例を示します。

class MyThreadClass
{
public:
   MyThreadClass() {/* empty */}
   virtual ~MyThreadClass() {/* empty */}

   /** Returns true if the thread was successfully started, false if there was an error starting the thread */
   bool StartInternalThread()
   {
      return (pthread_create(&_thread, NULL, InternalThreadEntryFunc, this) == 0);
   }

   /** Will not return until the internal thread has exited. */
   void WaitForInternalThreadToExit()
   {
      (void) pthread_join(_thread, NULL);
   }

protected:
   /** Implement this method in your subclass with the code you want your thread to run. */
   virtual void InternalThreadEntry() = 0;

private:
   static void * InternalThreadEntryFunc(void * This) {((MyThreadClass *)This)->InternalThreadEntry(); return NULL;}

   pthread_t _thread;
};

これを使用するには、スレッドのイベント ループを含めるために実装された InternalThreadEntry() メソッドを使用して MyThreadClass のサブクラスを作成するだけです。もちろん、スレッドオブジェクトを削除する前に、スレッドオブジェクトで WaitForInternalThreadToExit() を呼び出す必要があります(スレッドが実際に終了することを確認するメカニズムが必要です。そうしないと、WaitForInternalThreadToExit() が返されません)。

于 2009-07-20T03:38:30.510 に答える
10

pthread_create探している署名に一致する関数を指定する必要があります。渡したものは機能しません。

これを実行するために必要な静的関数を実装でき、そのインスタンスを参照cして、スレッドで必要なものを実行できます。pthread_create関数ポインタだけでなく、「コンテキスト」へのポインタを取るように設計されています。この場合、のインスタンスへのポインタを渡すだけですc

例えば:

static void* execute_print(void* ctx) {
    c* cptr = (c*)ctx;
    cptr->print();
    return NULL;
}


void func() {

    ...

    pthread_create(&t1, NULL, execute_print, &c[0]);

    ...
}
于 2009-07-20T03:21:25.490 に答える
3

上記の答えは良いですが、私の場合、関数を静的に変換する最初のアプローチは機能しませんでした。既存のコードを変換してスレッド関数に移動しようとしていましたが、そのコードにはすでに非静的クラス メンバーへの参照がたくさんありました。C++ オブジェクトにカプセル化する 2 番目のソリューションは機能しますが、スレッドを実行するための 3 レベルのラッパーがあります。

私は、既存の C++ 構造体である「friend」関数を使用する代替ソリューションを用意しましたが、それは私の場合には完璧に機能しました。「friend」の使用例 (friend を使用してコンパクトな形式に変換する方法を示す名前には、上記と同じ例を使用します)

    class MyThreadClass
    {
    public:
       MyThreadClass() {/* empty */}
       virtual ~MyThreadClass() {/* empty */}

       bool Init()
       {
          return (pthread_create(&_thread, NULL, &ThreadEntryFunc, this) == 0);
       }

       /** Will not return until the internal thread has exited. */
       void WaitForThreadToExit()
       {
          (void) pthread_join(_thread, NULL);
       }

    private:
       //our friend function that runs the thread task
       friend void* ThreadEntryFunc(void *);

       pthread_t _thread;
    };

    //friend is defined outside of class and without any qualifiers
    void* ThreadEntryFunc(void *obj_param) {
    MyThreadClass *thr  = ((MyThreadClass *)obj_param); 

    //access all the members using thr->

    return NULL;
    }

もちろん、boost::thread を使用してこれらすべてを回避することもできますが、C++ コードを変更して、boost を使用しないようにしようとしていました (コードは、この目的のためだけに boost に対してリンクしていました)。

于 2015-07-17T20:21:38.143 に答える
1

誰かに役立つことを期待しての私の最初の回答:これは古い質問ですが、TcpServerクラスを作成していて、pthreadsを使用しようとしていたときに、上記の質問とまったく同じエラーが発生しました。私はこの質問を見つけ、なぜそれが起こったのか理解しました。私はこれをやってしまった:

#include <thread>

スレッドを実行する方法 ->void* TcpServer::sockethandler(void* lp) {/*code here*/}

そして、ラムダで呼び出します->std::thread( [=] { sockethandler((void*)csock); } ).detach();

それは私にはきれいなアプローチのようです。

于 2016-08-30T14:35:29.793 に答える
0

これは少し古い質問ですが、多くの人が直面する非常に一般的な問題です。以下は、std::thread を使用してこれを処理するシンプルでエレガントな方法です。

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>

class foo
{
    public:
        void bar(int j)
        {
            n = j;
            for (int i = 0; i < 5; ++i) {
                std::cout << "Child thread executing\n";
                ++n;
                std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
        }
        int n = 0;
};

int main()
{
    int n = 5;
    foo f;
    std::thread class_thread(&foo::bar, &f, n); // t5 runs foo::bar() on object f
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    std::cout << "Main Thread running as usual";
    class_thread.join();
    std::cout << "Final value of foo::n is " << f.n << '\n';
}

上記のコードは、引数をスレッド関数に渡すことも処理します。

詳細については、 std::threadドキュメントを参照してください。

于 2019-10-03T10:53:32.540 に答える
-1

私の推測では、これは b/c が C++ によって少し混乱しているということです。b/c は、C 関数ポインターではなく、C++ ポインターを送信しています。明らかに違いがあります。してみてください

(void)(*p)(void) = ((void) *(void)) &c[0].print; //(check my syntax on that cast)

そして、pを送信します。

私はメンバー関数でもあなたがしていることをしましたが、それを使用していたクラスと静的関数でそれを行いました-それが違いを生んだと思います。

于 2009-07-20T03:31:23.020 に答える
-1

C++ : クラスメンバー関数を pthread_create() に渡す方法は?

http://thispointer.com/c-how-to-pass-class-member-function-to-pthread_create/

typedef void * (*THREADFUNCPTR)(void *);

class C { 
   // ...
   void *print(void *) { cout << "Hello"; }
}

pthread_create(&threadId, NULL, (THREADFUNCPTR) &C::print, NULL);
于 2017-08-22T23:43:43.553 に答える