395 Stimmen

Thread mit Mitgliederfunktion starten

Ich versuche, eine std::thread mit einer Mitgliedsfunktion, die keine Argumente annimmt und zurückgibt void . Ich kann keine Syntax finden, die funktioniert - der Compiler beschwert sich, egal was passiert. Was ist der richtige Weg zur Implementierung von spawn() so dass es eine std::thread die ausführt test() ?

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

496voto

Stephan Dollberg Punkte 31089
#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();
}

EDIT: Bei der Buchhaltung müssen Sie wie folgt vorgehen:

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

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

Die oben beschriebene Syntax ist im Sinne der INVOKE-Definition (§ 20.8.2.1) definiert:

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

  • (t1.*f)(t2, ..., tN) wenn f ein po ist Typs T oder ein Verweis auf ein Objekt eines von T abgeleiteten Typs ist;
  • ((*t1).*f)(t2, ..., tN), wenn f ein Zeiger auf eine Mitgliedsfunktion einer Klasse T ist und t1 nicht zu den im vorhergehenden Punkt beschriebenen Typen gehört Punkt beschriebenen Typen ist;
  • t1.*f, wenn N == 1 und f ein Zeiger auf Mitgliedsdaten einer Klasse T ist und t 1 ein Objekt vom Typ T oder ein
    Verweis auf ein Objekt des Typs T oder ein Verweis auf ein Objekt des Typs
    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 den aufrufenden Thread möglicherweise überleben müssen, und das Kopieren der Argumente garantiert dies. Wenn Sie stattdessen wirklich eine Referenz übergeben wollen, können Sie eine std::reference_wrapper erstellt von std::ref .

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

Auf diese Weise versprechen Sie, dass Sie dafür sorgen, dass die Argumente noch existieren, wenn der Thread sie bearbeitet.


Beachten Sie, dass alle oben genannten Punkte auch für folgende Bereiche gelten std::async y std::bind .

135voto

RnMss Punkte 3526

Da Sie C++11 verwenden, ist der Lambda-Ausdruck eine gute und saubere Lösung.

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

desde this-> weggelassen werden kann, könnte es zu verkürzt werden:

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

oder einfach (veraltet)

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

35voto

hop5 Punkte 367

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

Die Kompilierung 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)

33voto

@hop5 und @RnMss schlugen vor, C++11-Lambdas zu verwenden, aber wenn Sie mit Zeigern arbeiten, können Sie sie 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

Umgeschriebenes Beispiel aus 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;
}

1voto

Mohit Punkte 865

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

Ich möchte noch ein paar Dinge zu diesem Thema hinzufügen.

  1. Wie man mit Funktoren und Threads arbeitet. Bitte beachten Sie das folgende Beispiel.

  2. Der Thread erstellt seine eigene Kopie des Objekts, während er das Objekt weitergibt.

    #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, das Gleiche zu erreichen, ist die folgende:

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

    t.join();
}

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

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X