2010-07-05 7 views
5

Estoy usando subprocesamiento múltiple en mi aplicación con _beginthread y ahora mismo para esperar hasta que todos los hilos terminen Tengo bools globales que se establecen en verdadero a medida que se completa cada hilo, por lo que estoy en un ciclo while hasta entonces. Debe haber una manera más limpia de hacer esto?¿Manera correcta de verificar si los hilos están hechos?

Gracias

Respuesta

8

Puede utilizar WaitForMultipleObjects que esperar a que los hilos para terminar en el hilo principal.

+0

Si solo tiene una ID de hilo, primero tendrá que convertirla en una HANDLE llamando a [OpenThread] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms684335 (v = vs .85) .aspx). – rustyx

+2

No, ¡no llame a OpenThread! Si el hilo ya salió y la identificación fue reasignada, puede terminar con un control de un hilo aleatorio diferente. Use _beginthreadex, que devuelve un identificador a la cadena. (_beginthread también devuelve un identificador, pero (citando los documentos) "podría no ser válido o apuntar a otro subproceso". Nunca use _beginthread). – benrg

3

lo que quiere echar un vistazo a técnicas de sincronización es de rosca - afortunadamente hay un poco de información en MSDN que probablemente puede ayudarle. Es probable que desee utilizar Eventos y WaitHandles aquí están las cosas principales en MSDN: http://msdn.microsoft.com/en-us/library/ms681924%28v=VS.85%29.aspx hay una serie de ejemplos.

También hay algo de información sobre la sincronización en MFC (que puede o no puede resultar útil, añadido con fines de referencia): http://msdn.microsoft.com/en-us/library/975t8ks0%28VS.71%29.aspx

he hecho un poco de búsqueda, pero he tenido un mal rato tratando para rastrear alguna información útil para usted que no utiliza la implementación de MFC. Hay un buen tutorial aquí (http://www.informit.com/library/content.aspx?b=Visual_C_PlusPlus&seqNum=149) pero, de nuevo, usando MFC. Sin embargo, podría echar un vistazo a la implementación MFC de mutexes como un comienzo.

Por lo tanto, lo que se necesita para familiarizarse con las funciones y estructuras de sincronización - todo cubierto aquí en MSDN: http://msdn.microsoft.com/en-us/library/ms686679%28v=VS.85%29.aspx

+0

Definitivamente debe utilizar eventos en bools. – DanDan

2

Use _beginthreadex en su lugar. Ambos _beginthread y _beginthreadexreturn a thread handle, pero el hilo iniciado con _beginthread cierra automáticamente su mango cuando termina, por lo que su uso para la sincronización no es confiable.

El controlador de hilo se puede utilizar con una de las funciones de sincronización de Win32, como WaitForSingleObject o WaitForMultipleObjects.

Al finalizar, los mangos devueltos por _beginthreadex deben cerrarse con CloseHandle().

0

Windows proporciona eventos para que un hilo notifique a otro. Fuera de la caja, Visual C++ proporciona soporte para eventos solo dentro de MFC. Para una versión portátil que no sea MFC, verifique thread management classes de la biblioteca de Boost. Hacen que el inicio y la espera de los hilos sean mucho más fáciles, aunque no proporcionan acceso directo a todas las funciones de la API de Windows.

1

El método habitual es mantener todas las asas de hilo y luego esperar en cada asa. Cuando el identificador es señalado, el subproceso ha finalizado, por lo que se elimina del conjunto de subprocesos. Yo uso std::set<HANDLE> para realizar un seguimiento de los identificadores de subprocesos. Hay dos métodos diferentes para la espera en múltiples objetos en Windows:

  1. iterar sobre el conjunto y llamar WaitForSingleObject con un tiempo de espera en cada una
  2. Convertir el conjunto en una matriz o vector y llamar a WaitForMultipleObjects

El primero suena ineficiente, pero en realidad es el más directo y el menos propenso a errores de los dos.Si tiene que esperar a que todos los hilos, a continuación, utilizar el siguiente bucle:

std::set<HANDLE> thread_handles; // contains the handle of each worker thread 
while (!thread_handles.empty()) { 
    std::set<HANDLE> threads_left; 
    for (std::set<HANDLE>::iterator cur_thread=thread_handles.begin(), 
            last=thread_handles.end(); 
     cur_thread != last; ++cur_thread) 
    { 
     DWORD rc = ::WaitForSingleObject(*cur_thread, some_timeout); 
     if (rc == WAIT_OBJECT_0) { 
      ::CloseHandle(*cur_thread); // necessary with _beginthreadex 
     } else if (rc == WAIT_TIMEOUT) { 
      threads_left.add(cur_thread); // wait again 
     } else { 
      // this shouldn't happen... try to close the handle and hope 
      // for the best! 
      ::CloseHandle(*cur_thread); // necessary with _beginthreadex 
     } 
    } 
    std::swap(threads_left, thread_handles); 
} 

Usando WaitForMultipleObjects que esperar a que los hilos a fin es un poco más difícil de lo que parece. Lo siguiente esperará por todos los hilos; sin embargo, solo espera hilos WAIT_MAXIMUM_OBJECTS a la vez. Otra opción es pasar por cada página de hilos. Dejaré ese ejercicio al lector;)

DWORD large_timeout = (5 * 60 * 1000); // five minutes 
std::set<HANDLE> thread_handles; // contains the handle of each worker thread 
std::vector<HANDLE> ary;   // WaitForMultipleObjects wants an array... 
while (!thread_handles.empty()) { 
    ary.assign(thread_handles.begin(), thread_handles.end()); 
    DWORD rc = ::WaitForMultipleObjects(std::min(ary.size(), WAIT_MAXIMUM_OBJECTS), 
             &ary[0], FALSE, large_timeout); 
    if (rc == WAIT_FAILED) { 
     // handle a failure case... this is usually something pretty bad 
     break; 
    } else if (rc == WAIT_TIMEOUT) { 
     // no thread exited in five minutes... this can be tricky since one of 
     // the threads beyond the first WAIT_MAXIMUM_OBJECTS may have terminated 
    } else { 
     long idx = (rc - WAIT_OBJECT_0); 
     if (idx > 0 && idx < ary.size()) { 
      // the object at `idx` was signaled, this means that the 
      // thread has terminated. 
      thread_handles.erase(ary[idx]); 
      ::CloseHandle(ary[idx]); // necessary with _beginthreadex 
     } 
    } 
} 

Esto no es exactamente bonito, pero debería funcionar. Si confías en que todos tus hilos se cerrarán y no te molesta esperarlos, entonces puedes usar WaitForMultipleObjects(ary.size(), &ary[0], TRUE, INFINITE). Por lo general, esto no es muy seguro, ya que un hilo fuera de control causará que su aplicación bloquee indefinidamente y, solo funcionará si ary.size() es menor que MAXIMUM_WAIT_OBJECTS.

Por supuesto, la otra opción es encontrar una implementación de conjunto de subprocesos y usarla en su lugar. Escribir código de enhebrado no es muy divertido, especialmente una vez que tienes que apoyarlo en la naturaleza. Considere usar algo como boost::thread_group en su lugar.

0

Puede usar los objetos boost :: thread. Llame al join en el objeto y esperará a que el hilo termine.

Cuestiones relacionadas