357

我正在尝试std::thread使用不带参数并返回的成员函数构造 a void。我无法弄清楚任何有效的语法 - 编译器无论如何都会抱怨。什么是正确的实现方法,spawn()以便它返回一个std::thread执行的test()

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

5 回答 5

451
#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, t1, t2, ..., tN) 如下:

  • (t1.*f)(t2, ..., tN) 当 f 是指向类 T 的成员函数的指针且 t1 是类型 T 的对象或对类型 T 对象的引用或对从 T 派生的类型的对象;
  • ((*t1).*f)(t2, ..., tN) 当 f 是指向类 T 的成员函数的指针且 t1 不是上一项中描述的类型之一时;
  • t1.*f 当 N == 1 并且 f 是指向类 T 的成员数据的指针并且 t 1 是 T 类型的对象或对
    T 类型的对象的引用或对
    派生自的类型的对象的引用T;
  • (*t1).*f 当 N == 1 并且 f 是指向类 T 的成员数据的指针并且 t 1 不是上一项中描述的类型之一时;
  • f(t1, t2, ..., tN) 在所有其他情况下。

我要指出的另一个一般事实是,默认情况下,线程构造函数将复制传递给它的所有参数。这样做的原因是参数可能需要比调用线程更长,复制参数可以保证这一点。相反,如果你想真正传递一个引用,你可以使用std::reference_wrappercreated by std::ref

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

通过这样做,您承诺您将确保当线程对其进行操作时参数仍然存在。


请注意,上面提到的所有内容也可以应用于std::asyncstd::bind

于 2012-05-20T13:07:09.663 回答
123

由于您使用的是 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(); } )

于 2013-10-10T11:37:49.980 回答
34

这是一个完整的例子

#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)
于 2015-08-24T07:31:53.260 回答
26

@hop5 和 @RnMss 建议使用 C++11 lambdas,但是如果你处理指针,你可以直接使用它们:

#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;
}
于 2017-11-18T08:32:51.643 回答
1

一些用户已经给出了他们的答案并很好地解释了它。

我想添加更多与线程相关的内容。

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

实现相同目的的另一种方法是:

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

    t.join();
}

但是,如果您想通过引用传递对象,请使用以下语法:

void main()
{
    CB obj;
    //thread t(obj);
    thread t(std::ref(obj));
    t.join();
}
于 2017-02-20T18:43:31.317 回答