c++ - threads - thread was not declared in this scope
C++ 0x interrupciĆ³n de hilo (8)
De acuerdo con el borrador final de C ++ 0x, no hay forma de solicitar que finalice un hilo. Dicho esto, si es necesario, debemos implementar una solución de hágalo usted mismo.
Por otro lado, boost :: thread proporciona un mecanismo para interrumpir un hilo de manera segura .
En tu opinión, ¿cuál es la mejor solución? ¿Diseñaste tu propio "mecanismo de interrupción" cooperativo o te vuelves nativo?
Aquí está mi humilde implementación de un anulador de hilo (para C ++ 0x). Espero que sea útil.
// Class cancellation_point
#include <mutex>
#include <condition_variable>
struct cancelled_error {};
class cancellation_point
{
public:
cancellation_point(): stop_(false) {}
void cancel() {
std::unique_lock<std::mutex> lock(mutex_);
stop_ = true;
cond_.notify_all();
}
template <typename P>
void wait(const P& period) {
std::unique_lock<std::mutex> lock(mutex_);
if (stop_ || cond_.wait_for(lock, period) == std::cv_status::no_timeout) {
stop_ = false;
throw cancelled_error();
}
}
private:
bool stop_;
std::mutex mutex_;
std::condition_variable cond_;
};
// Usage example
#include <thread>
#include <iostream>
class ThreadExample
{
public:
void start() {
thread_ = std::unique_ptr<std::thread>(
new std::thread(std::bind(&ThreadExample::run, this)));
}
void stop() {
cpoint_.cancel();
thread_->join();
}
private:
void run() {
std::cout << "thread started/n";
try {
while (true) {
cpoint_.wait(std::chrono::seconds(1));
}
} catch (const cancelled_error&) {
std::cout << "thread cancelled/n";
}
}
std::unique_ptr<std::thread> thread_;
cancellation_point cpoint_;
};
int main() {
ThreadExample ex;
ex.start();
ex.stop();
return 0;
}
El uso de identificador nativo para cancelar un hilo es una mala opción en C ++ ya que necesita destruir todos los objetos asignados de pila. Esta fue la razón principal por la que no incluyeron una operación de cancelación.
Boost.Thread proporciona un mecanismo de interrupción, que debe agruparse en cualquier primitiva de espera. Como esto puede ser costoso como un mecanismo general, el estándar no lo ha incluido.
Tendrá que implementarlo usted mismo. Vea mi respuesta here a una pregunta similar sobre cómo implementar esto usted mismo. Para completar la solución, debe interrumpirse una interrupción cuando la interrupción es verdadera y el hilo debe detectar esta interrupción y finalizar.
Estoy de acuerdo con esta decisión. Por ejemplo, .NET permite abortar cualquier hilo de trabajo, y nunca uso esta característica y no recomiendo hacerlo a ningún programador profesional. Quiero decidirme a mí mismo, cuándo se puede interrumpir un hilo de trabajo y cuál es la forma de hacerlo. Es diferente para hardware, E / S, UI y otros hilos. Si el hilo se puede detener en cualquier lugar, esto puede causar un comportamiento del programa indefinido con la administración de recursos, transacciones, etc.
Implementar una solución de hágalo usted mismo tiene más sentido, y realmente no debería ser tan difícil de hacer. Necesitará una variable compartida que lea / escriba sincrónicamente, indicando si se le pide al hilo que finalice, y su hilo lee periódicamente de esta variable cuando se encuentra en un estado en el que puede interrumpirse de forma segura. Cuando desee interrumpir un hilo, simplemente escriba sincrónicamente esta variable y luego se unirá al hilo. Suponiendo que coopera de forma adecuada, debe tener en cuenta que la variable se ha escrito y cerrado, lo que hace que la función de unión ya no se bloquee.
Si fueras nativo, no ganarías nada con eso; simplemente descartaría todos los beneficios de un mecanismo de enhebrado OOP estándar y multiplataforma. Para que su código sea correcto, el hilo debería cerrarse cooperativamente, lo que implica la comunicación descrita anteriormente.
Mi implementación de subprocesos usa el idioma pimpl, y en la clase Impl tengo una versión para cada sistema operativo que soporte y también una que usa boost, por lo que puedo decidir cuál usar al construir el proyecto.
Decidí hacer dos clases: una es Thread, que solo tiene los servicios básicos provistos por OS; y el otro es SafeThread, que hereda de Thread y tiene un método para la interrupción colaborativa.
El subproceso tiene un método de terminación () que realiza una terminación intrusiva. Es un método virtual que está sobrecargado en SafeThread, donde señala un objeto de evento. Hay un método (estático) yeld () que el hilo en ejecución debe llamar de vez en cuando; este método verifica si el objeto del evento está señalizado y, si es así, arroja una excepción atrapada en la persona que llama del punto de entrada del hilo, terminando así el hilo. Cuando lo hace, señala un segundo objeto de evento para que la persona que llama de terminate () sepa que el hilo se detuvo de manera segura.
Para los casos en los que existe riesgo de interbloqueo, SafeThread :: terminate () puede aceptar un parámetro de tiempo de espera excedido. Si el tiempo de espera expira, llama a Thread :: terminate (), matando intrusivamente el hilo. Este es un último recurso cuando tienes algo que no puedes controlar (como una API de un tercero) o en situaciones en las que un interbloqueo hace más daño que las fugas de recursos y cosas por el estilo.
Espero que esto sea útil para su decisión y le dará una idea lo suficientemente clara sobre mis opciones de diseño. Si no, puedo publicar fragmentos de código para aclarar si lo desea.
No es seguro finalizar un hilo de manera preventiva porque el estado de todo el proceso se vuelve indeterminado después de ese punto. El hilo podría haber adquirido una sección crítica antes de ser terminado. Esa sección crítica ahora nunca será lanzada. El montón podría quedar bloqueado permanentemente, y así sucesivamente.
La solución boost::thread::interrupt
funciona preguntando muy bien. Solo interrumpirá un hilo haciendo algo que sea interrumpible, como esperar en una variable de condición Boost.Thread, o si el hilo hace una de estas cosas después de que se invoca la interrupción. Incluso entonces, el hilo no se coloca sin ceremonias en la picadora de carne ya que, digamos, la función TerminateThread
de Win32 sí lo hace, simplemente induce una excepción que, si has sido un codificador de buen comportamiento y usó RAII en todas partes, se limpiará después sí mismo y con gracia salir del hilo.
No es seguro finalizar un hilo, ya que no tendría control sobre el estado de las estructuras de datos en las que estaba trabajando en ese momento.
Si desea interrumpir un hilo en ejecución, debe implementar su propio mecanismo. En mi humilde opinión, si lo necesita, su diseño no está preparado para múltiples hilos.
Si solo quieres esperar a que termine un hilo, utiliza join () o un futuro.
Todas las especificaciones del lenguaje dicen que el soporte no está incorporado en el lenguaje. boost::thread::interrupt
necesita soporte de la función de subprocesos:
Cuando el hilo interrumpido ejecuta a continuación uno de los puntos de interrupción especificados (o si actualmente está bloqueado mientras ejecuta uno)
es decir, cuando la función de hilo no le da al que llama la oportunidad de interrumpir, usted todavía está atascado.
No estoy seguro de lo que quiere decir con "volverse nativo": no hay soporte nativo, a menos que esté hechizado para boost:threads
.
Aún así, utilizaría un mecanismo explícito. Tienes que pensar en tener suficientes puntos de interrupción de todos modos, ¿por qué no hacerlos explícitos? El código adicional suele ser marginal en mi experiencia, aunque es posible que necesite cambiar algunas esperas de un solo objeto a múltiples objetos, lo que, dependiendo de su biblioteca, puede parecer más feo.
También se podría extraer el "no usar excepciones para el flujo de control", pero en comparación con jugar con hilos, esto es solo una guía.