it-swarm.com.de

Starten Sie den Thread mit der Elementfunktion

Ich versuche, einen std::thread mit einer Mitgliedsfunktion zu konstruieren, die keine Argumente akzeptiert und void zurückgibt. Ich kann keine Syntax finden, die funktioniert - der Compiler beklagt sich, egal was passiert. Was ist der richtige Weg, um spawn() so zu implementieren, dass ein std::thread zurückgegeben wird, der test() ausführt?

#include <thread>
class blub {
  void test() {
  }
public:
  std::thread spawn() {
    return { test };
  }
};
257
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();
}

BEARBEITEN: Wenn du deine Bearbeitung abrechnest, musst du das so machen:

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

PDATE: Ich möchte noch einige Punkte erläutern, von denen einige auch in den Kommentaren besprochen wurden.

Die oben beschriebene Syntax ist in Bezug auf die INVOKE-Definition (§20.8.2.1) definiert:

Definieren Sie INVOKE (f, t1, t2, ..., tN) wie folgt:

  • (t1. * f) (t2, ..., tN), wenn f ein Zeiger auf eine Mitgliedsfunktion einer Klasse T ist und t1 ein Objekt vom Typ T oder eine Referenz auf ein Objekt vom Typ T oder eine Referenz auf eine ist Objekt eines von T abgeleiteten Typs;
  • ((* t1). * f) (t2, ..., tN), wenn f ein Zeiger auf eine Elementfunktion einer Klasse T ist und t1 nicht zu den im vorherigen Punkt beschriebenen Typen gehört;
  • t1. * f wenn N == 1 und f ein Zeiger auf Mitgliedsdaten einer Klasse T ist und t 1 ein Objekt vom Typ T oder a ist
    Verweis auf ein Objekt vom Typ T oder einen Verweis auf ein Objekt von a
    Typ abgeleitet von T;
  • (* t1). * f wenn N == 1 und f ein Zeiger auf Mitgliedsdaten einer Klasse T ist und t 1 nicht zu den im vorherigen Punkt beschriebenen Typen gehört;
  • f (t1, t2, ..., tN) in allen anderen Fällen.

Eine weitere allgemeine Tatsache, auf die ich hinweisen möchte, ist, dass der Thread-Konstruktor standardmäßig alle an ihn übergebenen Argumente kopiert. Der Grund dafür ist, dass die Argumente möglicherweise den aufrufenden Thread überleben müssen, und das Kopieren der Argumente dies garantiert. Wenn Sie eine Referenz wirklich übergeben möchten, können Sie stattdessen einen std::reference_wrapper verwenden, der von std::ref erstellt wurde.

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

Auf diese Weise versprechen Sie, dass Sie dafür sorgen werden, dass die Argumente auch dann noch vorhanden sind, wenn der Thread sie verarbeitet.


Beachten Sie, dass alle oben genannten Dinge auch auf std::async und std::bind angewendet werden können.

328
inf

Da Sie C++ 11 verwenden, ist Lambda-Ausdruck eine Nice & Clean-Lösung.

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

da this-> weggelassen werden kann, kann es verkürzt werden auf:

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

oder nur

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

Hier ist ein vollständiges Beispiel

#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;
}

Kompilieren mit g ++ führt zu folgendem Ergebnis

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 und @RnMss schlugen vor, C++ 11-Lambdas zu verwenden. Wenn Sie sich jedoch mit Zeigern befassen, können Sie diese direkt verwenden:

#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;
}

ausgänge

2

Umgeschriebene Probe von diese Antwort wäre dann:

#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;
}
14

Einige Benutzer haben ihre Antwort bereits gegeben und sie sehr gut erklärt.

Ich möchte noch ein paar Dinge zum Thema Thread hinzufügen.

  1. Wie man mit functor und thread arbeitet. Bitte beziehen Sie sich auf das folgende Beispiel.

  2. Der Thread erstellt beim Übergeben des Objekts eine eigene Kopie des Objekts.

    #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();
    }
    

Eine andere Möglichkeit, dasselbe zu erreichen, ist wie folgt:

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

    t.join();
}

Wenn Sie das Objekt jedoch als Referenz übergeben möchten, verwenden Sie die folgende Syntax:

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