c++ - sincronizar - Iniciar hilo con función miembro
suma con hilos en c (5)
Estoy intentando construir un std::thread
con una función miembro que no toma argumentos y devuelve void
. No puedo entender ninguna sintaxis que funcione - el compilador se queja sin importar qué. ¿Cuál es la forma correcta de implementar spawn()
para que devuelva un std::thread
que ejecute test()
?
#include <thread>
class blub {
void test() {
}
public:
std::thread spawn() {
return { test };
}
};
@ hop5 y @RnMss sugirieron usar las lambdas de C ++ 11, pero si trata con punteros, puede usarlos directamente:
#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;
}
salidas
2
La muestra reescrita de esta respuesta sería entonces:
#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;
}
Algunos usuarios ya han dado su respuesta y la han explicado muy bien.
Me gustaría añadir algunas cosas más relacionadas con el hilo.
Cómo trabajar con funtor e hilo. Por favor, consulte el siguiente ejemplo.
El hilo hará su propia copia del objeto al pasar el objeto.
#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(); }
Otra forma de lograr lo mismo es como:
void main()
{
thread t((CB()));
t.join();
}
Pero si desea pasar el objeto por referencia, use la siguiente sintaxis:
void main()
{
CB obj;
//thread t(obj);
thread t(std::ref(obj));
t.join();
}
Aquí hay un ejemplo completo.
#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;
}
Compilar con g ++ produce el siguiente resultado
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)
Ya que está utilizando C ++ 11, lambda-expresión es una solución agradable y limpia.
class blub {
void test() {}
public:
std::thread spawn() {
return std::thread( [this] { this->test(); } );
}
};
ya que this->
se puede omitir, se podría acortar a:
std::thread( [this] { test(); } )
o solo
std::thread( [=] { test(); } )
#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();
}
EDITAR: Teniendo en cuenta su edición, tiene que hacerlo así:
std::thread spawn() {
return std::thread(&blub::test, this);
}
ACTUALIZACIÓN: Quiero explicar algunos puntos más, algunos de ellos también se han discutido en los comentarios.
La sintaxis descrita anteriormente se define en términos de la definición de INVOKE (§20.8.2.1):
Defina INVOKE (f, t1, t2, ..., tN) de la siguiente manera:
- (t1. * f) (t2, ..., tN) cuando f es un puntero a una función miembro de una clase T y t1 es un objeto de tipo T o una referencia a un objeto de tipo T o una referencia a un objeto de un tipo derivado de T;
- ((* t1). * f) (t2, ..., tN) cuando f es un puntero a una función miembro de una clase T y t1 no es uno de los tipos descritos en el elemento anterior;
- t1. * f cuando N == 1 y f es un puntero a datos de miembros de una clase T y t 1 es un objeto de tipo T o
referencia a un objeto de tipo T o una referencia a un objeto de una
tipo derivado de T;- (* t1). * f cuando N == 1 y f es un puntero a datos de miembros de una clase T y t 1 no es uno de los tipos descritos en el elemento anterior;
- f (t1, t2, ..., tN) en todos los demás casos.
Otro hecho general que quiero señalar es que, de forma predeterminada, el constructor del hilo copiará todos los argumentos que se le pasen. El motivo de esto es que los argumentos pueden necesitar sobrevivir al subproceso que llama, al copiar los argumentos se lo garantiza. En cambio, si realmente quieres pasar una referencia, puedes usar un std::reference_wrapper
creado por std::ref
.
std::thread (foo, std::ref(arg1));
Al hacer esto, estás prometiendo que te encargarás de garantizar que los argumentos seguirán existiendo cuando el hilo funcione en ellos.
Tenga en cuenta que todas las cosas mencionadas anteriormente también se pueden aplicar a std::async
y std::bind
.