简体   繁体   English

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

[英]std::thread notation when defining the threaded function

I understand the std::thread notation presented here and reproduced as follows 我理解这里提供的std::thread符号并重现如下

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

because the definition of f1 and f2 is within main but fail to understand 因为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;
}

specifically the expression std::thread t1(&Threadme::run, Threadme()); 特别是表达式std::thread t1(&Threadme::run, Threadme()); as it relates to defining the threaded function run outside of main . 因为它涉及定义在main之外run的线程函数。 Why the reference & and why the thread parameters is a constructor invocation? 为什么引用&以及为什么线程parameters是构造函数调用?

&Foo::mem where Foo is a class type and mem a member (function or value) of Foo , is C++ notation for obtaining a pointer to a member (function or value). &Foo::mem其中Foo是一个类类型和mem中的一员(函数或值) Foo ,是用于获得一个指针指向一个构件(函数或值)C ++符号。 There exist a special syntax for invoking a member function pointer on an object, but this is usually sugared away by using std::mem_fun , which will turn a member function pointer into an ordinary function where the first argument has to be an object of the type the member function was taken from. 存在一种用于在对象上调用成员函数指针的特殊语法,但这通常通过使用std::mem_fun来消除,它将成员函数指针转换为普通函数,其中第一个参数必须是对象的对象。类型成员函数取自。

std::thread understands what is happening here and does exactly that: invoke Foo::mem on the object passed as the second argument. std::thread了解这里发生了什么,并且确实这样做:在作为第二个参数传递的对象上调用Foo::mem

A small example to reproduce this locally without actually involving std::thread : 在本地重现此实例而不实际涉及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
}

Why don't we need the mem_fun when constructing std::thread ? 为什么在构造std::thread时我们不需要mem_fun It automatically detects those situations through an overload and does the right thing all by itself. 它通过过载自动检测这些情况,并自行完成正确的事情。

You can see a member function of ThreadMe as a function that accepts an implicit first parameter of type ThreadMe* - also known as this . 您可以将ThreadMe的成员函数看作是接受ThreadMe*类型的隐式第一个参数的ThreadMe* - 也称为this This analogy is not 100% correct and might be shred to pieces by some language lawyer, but it serves for understanding the call you have there. 这个比喻并非100%正确,可能会被一些语言律师粉碎,但它有助于理解你在那里的电话。

std::thread and many other classes/functions that accept functions and parameters for them, like eg std::bind and std::function accept pointers to member functions, followed by an object on which the function has to be called, or put otherwise, followed by that implicit first parameter. std::thread和许多其他类/函数接受它们的函数和参数,例如std::bindstd::function接受指向成员函数的指针,后跟一个必须在其上调用函数的对象,或放入否则,后跟隐含的第一个参数。

So void ThreadMe::run() can be seen as void run(ThreadMe&); 所以void ThreadMe::run()可以看作是void run(ThreadMe&); Then the call that bothers you is easy to understand. 然后,困扰你的电话很容易理解。 Consider your second example: 考虑你的第二个例子:

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

now create the int just when it's needed: 现在在需要时创建int:

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

with ints that might not make so much sense, but with an object it does: 使用可能没有那么多意义的整数,但它有一个对象:

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

and since we know thet member functions are just a bit more than syntactic sugar for that implicit first argument, the call you have is still nothing else but the 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.

If you know lambdas, this is very similar, ie it passes a copy of a fresh ThreadMe to the thread that calls run on that copy:: 如果你知道lambdas,这是非常相似的,即它将一个新的ThreadMe的副本传递给调用该副本上运行的线程::

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

In fact, since the binding of parameters to functions that happens under the hood of std::thread 's constructor is somewhat unusual, I prefer using lambdas, since they explain explicitly anything the thread has to do. 事实上,由于参数绑定到std::thread的构造函数引擎下的函数有点不寻常,我更喜欢使用lambdas,因为它们明确解释了线程必须做的任何事情。 In this case I would not create that temporary ThreadMe to call the thread, I would create a nontemporary inside the thread itself: 在这种情况下,我不会创建临时ThreadMe来调用线程,我会在线程内部创建一个非临时的:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM