定义线程函数时的std :: thread表示法

时间:2013-04-30 12:40:35

标签: c++ multithreading

我理解std::thread符号here,并转载如下

#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>

void f1(int n)
{
    for (int i = 0; i < 5; ++i) {
    std::cout << "Thread " << n << " executing\n";
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

void f2(int& n)
{
    for (int i = 0; i < 5; ++i) {
        std::cout << "Thread 2 executing\n";
        ++n;
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
}

int main()
{
    int n = 0;
    std::thread t1; // t1 is not a thread
    std::thread t2(f1, n + 1); // pass by value
    std::thread t3(f2, std::ref(n)); // pass by reference
    std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
    t2.join();
    t4.join();
    std::cout << "Final value of n is " << n << '\n';
}

因为f1f2的定义在main范围内但未能理解

#ifndef THREADED_H_
#define THREADED_H_

class Threadme
{
    long count;

public:

    Threadme();

    void run(void);

    void delay(long);
};

#endif

#include "threaded.h"
#include <iostream>
#include <chrono>

Threadme::Threadme() : count(0) {}

void Threadme::delay(long seconds)
{
    std::chrono::steady_clock::time_point end_t = std::chrono::system_clock::now() + std::chrono::seconds(seconds);

    while(std::chrono::system_clock::now() < end_t)
       ;
}

void Threadme::run(void)
{
    while(count < 10)
    {
        ++count;

        std::cout << count << std::endl;

        delay(1);
    }

}

#include <cstdlib>
#include <thread>

#include "threaded.h"

int main(int argc, char *argv[]){

    std::thread t1(&Threadme::run, Threadme());

    t1.join();

    return EXIT_SUCCESS;
}

特别是表达式std::thread t1(&Threadme::run, Threadme());,因为它与定义run之外的线程函数main有关。为什么引用&以及为什么线程parameters是构造函数调用?

2 个答案:

答案 0 :(得分:3)

&Foo::mem其中Foo是类类型而memFoo的成员(函数或值),是用于获取指向成员的指针的C ++表示法(函数)或价值)。存在一种用于在对象上调用成员函数指针的特殊语法,但这通常通过使用std::mem_fun来消除,这会将成员函数指针转换为普通函数,其中第一个参数必须是成员函数的类型取自。

std::thread理解这里发生的事情并完全做到这一点:对作为第二个参数传递的对象调用Foo::mem

在本地重现此内容而不实际涉及std::thread的小例子:

#include <functional>

class Foo { void mem() {} };

int main() {
  Foo f;
  f.mem(); // normal invoke
  auto func = std::mem_fun(&Foo::mem);

  func(std::ref(f)); // invoke mem on f
  func(f); // invoke mem on a copy of f
  func(&f); // invoke mem on f through a pointer
}

为什么在构建mem_fun时我们不需要std::thread?它 通过过载自动检测这些情况 这是正确的事情。

答案 1 :(得分:-1)

您可以将ThreadMe的成员函数视为接受类型为ThreadMe*的隐式第一个参数的函数 - 也称为this。这个类比不是100%正确,可能会被一些语言律师粉碎,但它有助于理解你在那里的电话。

std::thread和许多其他接受函数和参数的类/函数,例如: std::bindstd::function接受指向成员函数的指针,后跟一个必须在其上调用函数的对象,否则放入该隐含的第一个参数。

所以void ThreadMe::run()可以被视为void run(ThreadMe&);那么困扰你的电话很容易理解。考虑你的第二个例子:

void f1(int n);
int n;
std::thread t2(f, n); //calls f in a new thread, passing n

现在只在需要时创建int:

std::thread t2(f, int()); //calls f, passing a copy of the int that has been created here...

对于可能没有多大意义的整数,但是它有一个对象:

void run(ThreadMe&);
std::thread t1(run, ThreadMe()); //conceptually the same as above

既然我们知道这个隐含的第一个参数的成员函数只比语法糖多一点,那么你所拥有的调用仍然只是上面的内容:

void ThreadMe::run(); //implicit first argument is a ThreadMe&
std::thread t1(ThreadMe::run, ThreadMe()); //pass a copy of that newly created ThreadMe as the implicit first argument of the run method.

如果你知道lambdas,这非常相似,即它将一个新的ThreadMe的副本传递给调用该副本上运行的线程::

ThreadMe threadMe;
std::thread t1([=](){ threadMe.run(); });

事实上,由于参数绑定到std::thread构造函数引擎下发生的函数有点不寻常,我更喜欢使用lambdas,因为它们明确解释了线程必须做的任何事情。在这种情况下,我不会创建临时ThreadMe来调用线程,我会在线程内部创建一个非临时的:

std::thread t1([](){ 
  ThreadMe threadMe;
  threadMe.run(); 
});