首页 文章

使用成员函数启动线程

提问于
浏览
236

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

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

5 回答

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

    UPDATE: 我想解释一些问题,其中一些也在评论中进行了讨论 .

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


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

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

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


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

  • 0

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

    这是一个完整的例子

    #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)
    
  • 9

    @ 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
    

    然后从this answer重写样本:

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

    一些用户已经给出了答案并对其进行了很好的解释 .

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

    • 如何使用仿函数和线程 . 请参考以下示例 .

    • 线程将在传递对象时创建自己的对象副本 .

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

相关问题