C++ 使用成员函数启动线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10673585/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:19:21  来源:igfitidea点击:

Start thread with member function

c++multithreadingc++11

提问by abergmeier

I am trying to construct a std::threadwith a member function that takes no arguments and returns void. I can't figure out any syntax that works - the compiler complains no matter what. What is the correct way to implement spawn()so that it returns a std::threadthat executes test()?

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

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

回答by Stephan Dollberg

#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: Accounting your edit, you have to do it like this:

编辑:会计你的编辑,你必须这样做:

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


UPDATE:I want to explain some more points, some of them have also been discussed in the comments.

更新:我想再解释一些要点,其中一些也在评论中讨论过。

The syntax described above is defined in terms of the INVOKE definition (§20.8.2.1):

上述语法是根据 INVOKE 定义(第 20.8.2.1 节)定义的:

Define INVOKE (f, t1, t2, ..., tN) as follows:

  • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
  • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
  • t1.*f when N == 1 and f is a pointer to member data of a class T and t 1 is an object of type T or a
    reference to an object of type T or a reference to an object of a
    type derived from T;
  • (*t1).*f when N == 1 and f is a pointer to member data of a class T and t 1 is not one of the types described in the previous item;
  • f(t1, t2, ..., tN) in all other cases.

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


Another general fact which I want to point out is that by default the thread constructor will copy all arguments passed to it. The reason for this is that the arguments may need to outlive the calling thread, copying the arguments guarantees that. Instead, if you want to really pass a reference, you can use a std::reference_wrappercreated by std::ref.

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

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

By doing this, you are promising that you will take care of guaranteeing that the arguments will still exist when the thread operates on them.

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



Note that all the things mentioned above can also be applied to std::asyncand std::bind.

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

回答by RnMss

Since you are using C++11, lambda-expression is a nice&clean solution.

由于您使用的是 C++11,因此 lambda 表达式是一个不错且干净的解决方案。

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

since this->can be omitted, it could be shorten to:

由于this->可以省略,因此可以缩短为:

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

or just

要不就

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

回答by hop5

Here is a complete example

这是一个完整的例子

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

Compiling with g++ produces the following result

用 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)

回答by Andrey Starodubtsev

@hop5 and @RnMss suggested to use C++11 lambdas, but if you deal with pointers, you can use them directly:

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

outputs

产出

2

Rewritten sample from this answerwould be then:

从此答案重写的样本将是:

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

回答by Mohit

Some users have already given their answer and explained it very well.

有的用户已经给出了答案,并且解释的很好。

I would like to add few more things related to thread.

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

  1. How to work with functor and thread. Please refer to below example.

  2. The thread will make its own copy of the object while passing the object.

    #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. 如何使用函子和线程。请参考下面的例子。

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

Another way of achieving the same thing is like:

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

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

    t.join();
}

But if you want to pass the object by reference then use the below syntax:

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

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