web-dev-qa-db-ja.com

メンバー関数でスレッドを開始

引数を取らずvoidを返すメンバー関数を使ってstd::threadを構築しようとしています。私はうまくいく構文を理解することはできません - コンパイラは何に関係なく文句を言います。 spawn()を実行するstd::threadを返すようにtest()を実装する正しい方法は何ですか?

#include <thread>
class blub {
  void test() {
  }
public:
  std::thread spawn() {
    return { test };
  }
};
246
abergmeier
#include <thread>
#include <iostream>

class bar {
public:
  void foo() {
    std::cout << "hello from member function" << std::endl;
  }
};

int main()
{
  std::thread t(&bar::foo, bar());
  t.join();
}

編集:あなたの編集を会計、あなたはこのようにそれをする必要があります:

  std::thread spawn() {
    return std::thread(&blub::test, this);
  }

更新: 私はいくつかのより多くの点を説明したいのですが、それらのいくつかはまたコメントで議論されています。

上記の構文はINVOKE定義(20.8.2.1)によって定義されています。

INVOKE(f、t 1、t 2、...、t N)を次のように定義します。

  • (t1。* f)(t2、...、tN)fがクラスTのメンバ関数へのポインタで、t1が型Tのオブジェクトまたは型Tのオブジェクトへの参照、またはTから派生した型のオブジェクト。
  • ((* t1)。* f)(t2、...、tN)fがクラスTのメンバ関数へのポインタであり、t1が前の項目で説明した型のいずれでもない場合。
  • n == 1で、fがクラスTのメンバデータへのポインタで、t 1が型Tまたはaのオブジェクトの場合、t1。* f
    タイプTのオブジェクトへの参照、またはタイプTのオブジェクトへの参照
    Tから派生したタイプ。
  • (* t1)。* f N == 1で、fがクラスTのメンバデータへのポインタであり、かつt 1が前の項目で説明した型のいずれでもない場合。
  • 他の全ての場合において、f(t 1、t 2、…、t N)である。

私が指摘したいもう一つの一般的な事実は、デフォルトでスレッドコンストラクタがそれに渡されたすべての引数をコピーするということです。その理由は、引数が呼び出し側スレッドより長生きする必要があり、引数をコピーすることでそれが保証されるためです。代わりに、実際に参照を渡したい場合は、std::reference_wrapperによって作成されたstd::refを使用できます。

std::thread (foo, std::ref(arg1));

こうすることで、スレッドが引数を操作するときに引数が存在することを保証するように気を配ることになります。


上記のことはすべてstd::asyncstd::bindにも適用できることに注意してください。

313
inf

C++ 11を使用しているので、lambda-expressionは素晴らしくクリーンなソリューションです。

class blub {
    void test() {}
  public:
    std::thread spawn() {
      return std::thread( [this] { this->test(); } );
    }
};

this->は省略できるので、次のように短くすることができます。

std::thread( [this] { test(); } )

あるいは単に

std::thread( [=] { test(); } )
83
RnMss

これが完全な例です

#include <thread>
#include <iostream>

class Wrapper {
   public:
      void member1() {
          std::cout << "i am member1" << std::endl;
      }
      void member2(const char *arg1, unsigned arg2) {
          std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
      }
      std::thread member1Thread() {
          return std::thread([=] { member1(); });
      }
      std::thread member2Thread(const char *arg1, unsigned arg2) {
          return std::thread([=] { member2(arg1, arg2); });
      }
};
int main(int argc, char **argv) {
   Wrapper *w = new Wrapper();
   std::thread tw1 = w->member1Thread();
   std::thread tw2 = w->member2Thread("hello", 100);
   tw1.join();
   tw2.join();
   return 0;
}

G ++でコンパイルすると、次のようになります。

g++ -Wall -std=c++11 hello.cc -o hello -pthread

i am member1
i am member2 and my first arg is (hello) and second arg is (100)
27
hop5

@ hop5と@RnMssはC++ 11のラムダを使うことを提案しました、しかしあなたがポインタを扱うならば、あなたは直接それらを使うことができます:

#include <thread>
#include <iostream>

class CFoo {
  public:
    int m_i = 0;
    void bar() {
      ++m_i;
    }
};

int main() {
  CFoo foo;
  std::thread t1(&CFoo::bar, &foo);
  t1.join();
  std::thread t2(&CFoo::bar, &foo);
  t2.join();
  std::cout << foo.m_i << std::endl;
  return 0;
}

アウトプット

2

からの書き換えられたサンプル - この答え は、

#include <thread>
#include <iostream>

class Wrapper {
  public:
      void member1() {
          std::cout << "i am member1" << std::endl;
      }
      void member2(const char *arg1, unsigned arg2) {
          std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
      }
      std::thread member1Thread() {
          return std::thread(&Wrapper::member1, this);
      }
      std::thread member2Thread(const char *arg1, unsigned arg2) {
          return std::thread(&Wrapper::member2, this, arg1, arg2);
      }
};

int main() {
  Wrapper *w = new Wrapper();
  std::thread tw1 = w->member1Thread();
  tw1.join();
  std::thread tw2 = w->member2Thread("hello", 100);
  tw2.join();
  return 0;
}
12

何人かのユーザーは既に彼らの答えを与え、それを非常によく説明しています。

スレッドに関するいくつかのことを追加したい。

  1. ファンクターとスレッドの使い方下記の例を参照してください。

  2. オブジェクトを渡す間、スレッドはそれ自身のオブジェクトのコピーを作成します。

    #include<thread>
    #include<Windows.h>
    #include<iostream>
    
    using namespace std;
    
    class CB
    {
    
    public:
        CB()
        {
            cout << "this=" << this << endl;
        }
        void operator()();
    };
    
    void CB::operator()()
    {
        cout << "this=" << this << endl;
        for (int i = 0; i < 5; i++)
        {
            cout << "CB()=" << i << endl;
            Sleep(1000);
        }
    }
    
    void main()
    {
        CB obj;     // please note the address of obj.
    
        thread t(obj); // here obj will be passed by value 
                       //i.e. thread will make it own local copy of it.
                        // we can confirm it by matching the address of
                        //object printed in the constructor
                        // and address of the obj printed in the function
    
        t.join();
    }
    

同じことを実現するもう1つの方法は次のとおりです。

void main()
{
    thread t((CB()));

    t.join();
}

しかし、オブジェクトを参照渡しにしたい場合は、以下の構文を使用してください。

void main()
{
    CB obj;
    //thread t(obj);
    thread t(std::ref(obj));
    t.join();
}
0
Mohit