waitforsingleobject waitformultipleobjects c++ multithreading winapi dll

c++ - waitforsingleobject - waitformultipleobjects msdn



WaitForSingleObject para el objeto thread no funciona en DLL descarga (1)

Me encontré con un comportamiento inesperado del mecanismo de subprocesos de Windows cuando se descarga DLL. A tengo un paquete de objetos de subprocesos de trabajo y estoy tratando de terminarlos gentilmente cuando se descarga DLL (a través de DllMain DLL_PROCESS_DETACH). El código es muy simple (envié un evento para finalizar el ciclo de espera de la secuencia):

WaitForSingleObject( ThrHandle, INFINITE ); CloseHandle( ThrHandle );

Sin embargo, WaitForSingleObject cuelga todo. Funciona bien si lo realizo antes de que se descargue DLL. ¿Cómo se puede arreglar este comportamiento?


No puede esperar a que salga un subproceso en DllMain (). A menos que el hilo ya haya salido antes de que se recibiera DLL_PROCESS_DETACH, hacerlo siempre será un punto muerto. Este es el comportamiento esperado.

El motivo es que las llamadas a DllMain () se serializan a través del bloqueo del cargador. Cuando se invoca ExitThread (), reclama el bloqueo del cargador para que pueda llamar a DllMain () con DLL_THREAD_DETACH. Hasta que la llamada finalice, el hilo aún se está ejecutando.

Así que DllMain está esperando a que salga el hilo, y el hilo está esperando a que DllMain salga, una situación clásica de punto muerto.

Consulte también las Mejores prácticas de bibliotecas de enlace dinámico en MSDN.

La solución es agregar una nueva función a su DLL para que la aplicación llame antes de descargar la DLL. Como ha notado, su código ya funciona perfectamente bien cuando se lo llama explícitamente.

En el caso en que los requisitos de compatibilidad retroactiva hagan que sea imposible agregar dicha función, y si debe tener los subprocesos de trabajo, considere dividir su DLL en dos partes, una de las cuales se carga dinámicamente por la otra. La parte cargada dinámicamente contendría (como mínimo) todo el código necesario para los hilos de trabajo.

Cuando la DLL que fue cargada por la aplicación recibe DLL_PROCESS_DETACH, simplemente establece el evento para indicar a los hilos que salgan y luego regresen inmediatamente. Uno de los subprocesos tendría que estar designado para esperar a todos los demás y luego liberar el segundo DLL, que puede hacer de manera segura utilizando FreeLibraryAndExitThread () .

(Dependiendo de las circunstancias y, en particular, si los hilos de trabajo están saliendo y / o se están creando otros nuevos como parte de las operaciones regulares, es posible que deba tener mucho cuidado para evitar condiciones de carrera y / o interbloqueos, esto sería más simple si utilizó un grupo de subprocesos y devoluciones de llamada en lugar de crear subprocesos de trabajo manualmente).

En el caso especial donde los subprocesos no necesitan usar nada más que las API de Windows más simples, es posible usar un grupo de subprocesos y devoluciones de llamada de trabajo para evitar la necesidad de una segunda DLL. Una vez que hayan salido las devoluciones de llamada, que puede verificar utilizando WaitForThreadpoolWorkCallbacks () , es seguro que la biblioteca se descargue; no es necesario que espere a que salgan los hilos.

La trampa aquí es que las devoluciones de llamada deben evitar cualquier API de Windows que pueda tomar el bloqueo del cargador. No está documentado qué llamadas API son seguras a este respecto, y varía según las diferentes versiones de Windows. Si llama a algo más complicado que SetEvent o WriteFile, por ejemplo, o si está utilizando una biblioteca en lugar de las funciones nativas de la API de Windows, no debe utilizar este enfoque.