Subprocesamiento de Windows: _beginthread vs _beginthreadex vs CreateThread C ++


133

¿Cuál es una mejor manera de comenzar un hilo _beginthread, _beginthreadxo CreateThread?

Estoy tratando de determinar cuáles son las ventajas / desventajas de _beginthread, _beginthreadexy CreateThread. Todas estas funciones devuelven un identificador de subproceso a un subproceso recién creado, ya sé que CreateThread proporciona un poco de información adicional cuando se produce un error (se puede verificar llamando GetLastError) ... pero ¿cuáles son algunas cosas que debo considerar cuando ' Estoy usando estas funciones?

Estoy trabajando con una aplicación de Windows, por lo que la compatibilidad multiplataforma ya está fuera de discusión.

He revisado la documentación de msdn y simplemente no puedo entender, por ejemplo, por qué alguien decidiría usar _beginthread en lugar de CreateThread o viceversa.

¡Salud!

Actualización: OK, gracias por toda la información, también he leído en un par de lugares a los que no puedo llamar WaitForSingleObject()si los usaba _beginthread(), pero si llamo _endthread()en el hilo, ¿no debería funcionar? ¿Cuál es el trato allí?


2
Aquí hay un análisis de lo que _beginthreadex () hace para los programadores de C / C ++ que encontré en un enlace en el sitio web de Eli Bendersky. Esto es de un Q&A sobre si usar CreateThread () o no. microsoft.com/msj/0799/win32/win320799.aspx
Richard Chambers

Respuestas:


96

CreateThread() es una llamada API de Win32 sin procesar para crear otro subproceso de control a nivel del núcleo.

_beginthread()& _beginthreadex()son llamadas de biblioteca de tiempo de ejecución C que llaman CreateThread()detrás de escena. Una vez que CreateThread()ha regresado, _beginthread/ex()se encarga de la contabilidad adicional para que la biblioteca de tiempo de ejecución C sea utilizable y coherente en el nuevo hilo.

En C ++, seguramente debería usarlo a _beginthreadex()menos que no se vincule a la biblioteca de tiempo de ejecución de C (también conocido como MSVCRT * .dll / .lib).


39
Esto ya no es tan cierto como solía ser. El CRT funcionará correctamente en un hilo creado por CreateThread () con la excepción de la función signal (). Habrá una pequeña pérdida de memoria (~ 80 bytes) para cada hilo creado con CreateThread () que usa el CRT, pero funcionará correctamente. Consulte para obtener más información: support.microsoft.com/default.aspx/kb/104641
John Dibling

1
@John: En realidad, ese error se aplica solo hasta MSVC ++ 6.0
bobobobo

55
@bobobobo: Buena pregunta. Solo puedo especular que MS originalmente pretendía que las _beginrutinas fueran llamadas internas y CreateThreadse suponía que era la función API que todos llamarían. Otra posible explicación es que la EM tiene una larga y gloriosa historia de ignorar el estándar y tomar decisiones muy malas sobre nombrar cosas.
John Dibling el

15
Las _beginfunciones comienzan con un guión bajo porque Microsoft comenzó a seguir el estándar más de cerca. En el tiempo de ejecución de C, los nombres que están con guión bajo están reservados para la implementación (y la implementación puede documentarlos para el uso del usuario final, como con estos). beginthreadex()es un nombre que el usuario puede usar. Si el tiempo de ejecución C lo usó, entonces podría entrar en conflicto con un símbolo de usuario final que el usuario tenía el derecho legítimo de poder esperar usar. Tenga en cuenta que las API de Win32 no forman parte del tiempo de ejecución de C y utilizan el espacio de nombres del usuario.
Michael Burr

2
@Lothar: No hay diferencias entre la llamada a la API de Win32 CreateThready las llamadas CRT _beginthread/ex, y al llamar al CRT en un hilo, que siempre deben ser creados con _beginthread/ex. Es posible que ya no haya pérdidas de memoria, si no lo hace. Pero seguramente no obtendrá su entorno de punto flotante correctamente inicializado cuando llame CreateThread, por ejemplo. Hay más : "Si un hilo creado usando CreateThread llama al CRT, el CRT puede terminar el proceso en condiciones de poca memoria".
Inspeccionable

37

Hay varias diferencias entre _beginthread()y _beginthreadex(). _beginthreadex()fue hecho para actuar más como CreateThread()(en ambos parámetros y cómo se comporta).

Como Drew Hall menciona, si está utilizando el tiempo de ejecución C / C ++, debe usar _beginthread()/ en _beginthreadex()lugar de CreateThread()para que el tiempo de ejecución tenga la oportunidad de realizar su propia inicialización de subprocesos (configuración del almacenamiento local de subprocesos, etc.).

En la práctica, esto significa que CreateThread()su código nunca debería ser usado directamente por su código.

Los documentos de MSDN para _beginthread()/ _beginthreadex()tienen bastante detalle sobre las diferencias, una de las más importantes es que, dado que el identificador de hilo para un hilo creado por _beginthread()se cierra automáticamente por el CRT cuando el hilo sale, "si el hilo generado por _beginthread sale rápidamente, el identificador devuelto al llamador de _beginthread podría no ser válido o, peor aún, señalar a otro hilo ".

Esto es lo que dicen los comentarios _beginthreadex()en la fuente CRT:

Differences between _beginthread/_endthread and the "ex" versions:

1)  _beginthreadex takes the 3 extra parameters to CreateThread
  which are lacking in _beginthread():
    A) security descriptor for the new thread
    B) initial thread state (running/asleep)
    C) pointer to return ID of newly created thread

2)  The routine passed to _beginthread() must be __cdecl and has
  no return code, but the routine passed to _beginthreadex()
  must be __stdcall and returns a thread exit code.  _endthread
  likewise takes no parameter and calls ExitThread() with a
  parameter of zero, but _endthreadex() takes a parameter as
  thread exit code.

3)  _endthread implicitly closes the handle to the thread, but
  _endthreadex does not!

4)  _beginthread returns -1 for failure, _beginthreadex returns
  0 for failure (just like CreateThread).

Actualización de enero de 2013:

El CRT para VS 2012 tiene un bit de inicialización adicional realizado _beginthreadex(): si el proceso es una "aplicación empaquetada" (si se devuelve algo útil GetCurrentPackageId()), el tiempo de ejecución inicializará el MTA en el subproceso recién creado.


3
No son momentos adecuados cuando se justifique CreateThread (), pero la verdad es que realmente tienen que salir de su manera de hacerlo. Estamos hablando de una falta total de nada portátil y escribiendo una DLL o aplicación de API WIN32 exclusivamente. No incluye llamadas de tiempo de ejecución C. Incluso el uso de STL es limitado, ya que debe proporcionar asignadores personalizados para usar las funciones de administración de memoria WIN32. La configuración para hacer esto con Developer Studio es un trabajo en sí mismo, pero para una lib WIN32 única con la menor huella posible, se puede hacer. Pero sí, no es muy probable para casi todos, excepto para unos pocos muy selectos.
WhozCraig

1
@WhozCraig: Existen limitaciones más severas al omitir el CRT. Los más destacados son: sin soporte de enteros de 64 bits, sin soporte de punto flotante y, lo más drástico, sin manejo de excepciones. Esto realmente significa que no hay manejo de excepciones, en absoluto . Ni siquiera las excepciones SEH. Esto es particularmente difícil de compensar, y las posibilidades de llamar a CreateThreadser lo correcto son cada vez más escasas.
Inspeccionable el

@MichaelBurr: es posible que desee actualizar su respuesta para VC ++ 2015 .
user541686

@Mehrdad: ¿Qué cambios específicamente encuentra que vale la pena mencionar?
Inspectable el

Descubrí que DisableThreadLibraryCalls no tiene ningún efecto en los hilos creados con CreateThread, pero sí deshabilita los hilos creados con _beginthread o _beginthreadex.
Abierto el

23

En general, lo correcto es llamar _beginthread()/_endthread()(o las ex()variantes). Sin embargo, si se utiliza el CRT como .dll, el estado CRT se ha inicializado correctamente y destruido como el CRT DllMainse llamará con DLL_THREAD_ATTACHy DLL_THREAD_DETACHal llamar CreateThread()y ExitThread()o regresar, respectivamente.

El DllMaincódigo para el CRT se puede encontrar en el directorio de instalación de VS en VC \ crt \ src \ crtlib.c.


Gran punto de partida. Con una pequeña depuración se puede mostrar que se llama a __CRTDLL_INIT incluso para un CRT estáticamente vinculado. Callstack el init se llama desde _LdrpCallInitRoutine @ 16 (), no estoy seguro exactamente por qué mecanismo. Esto significa que con la CRT reciente, toda la inicialización / desinicialización se realiza correctamente con la excepción del manejo de la señal, que todavía se realiza en la función auxiliar _threadstartex llamada desde beginthread, pero no desde CreateThread. ¿Quizás podría agregar esto a la respuesta y le otorgaré la recompensa?
Suma

Recompensa otorgada, ya que esto parece más útil. Aún así, quizás valga la pena actualizar la respuesta. Si no puede hacerlo, podría volver a visitarlo dentro de unos días.
Suma

1
@MSN: Tenga en cuenta que CreateThread todavía es malo en un archivo DLL, si está vinculando contra el CRT estático y ha llamado a DisableThreadLibraryCalls que desactiva las llamadas para DLL_THREAD_DETACH. Entonces obtendrá pérdidas de memoria. Esto está documentado aquí en mi artículo de KB: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach

17

Este es el código en el núcleo de _beginthreadex(ver crt\src\threadex.c):

    /*
     * Create the new thread using the parameters supplied by the caller.
     */
    if ( (thdl = (uintptr_t)
          CreateThread( (LPSECURITY_ATTRIBUTES)security,
                        stacksize,
                        _threadstartex,
                        (LPVOID)ptd,
                        createflag,
                        (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
    {
            err = GetLastError();
            goto error_return;
    }

El resto de _beginthreadexinicializa la estructura de datos por hilo para CRT.

La ventaja de usar _beginthread*es que sus llamadas CRT desde el hilo funcionarán correctamente.


12

Debería usar _beginthreado _beginthreadexpermitir que la biblioteca de tiempo de ejecución C haga su propia inicialización del hilo. Solo los programadores de C / C ++ necesitan saber esto, ya que ahora deberían conocer las reglas de uso de su propio entorno de desarrollo.

Si lo usa _beginthread, no necesita llamar, CloseHandleya que RTL lo hará por usted. Es por eso que no puede esperar en el mango si lo ha usado _beginthread. También _beginthreadconduce a la confusión si la función de subproceso sale inmediatamente (rápidamente) ya que el subproceso de inicio puede quedar sosteniendo un identificador de subproceso no válido para el subproceso que acaba de iniciar.

_beginthreadexlos identificadores se pueden usar para esperar pero también requieren una llamada explícita a CloseHandle. Esto es parte de lo que los hace seguros para usar con wait. Otro problema para que sea completamente infalible es siempre iniciar el hilo suspendido. Verifique el éxito, identificador de registro, etc. El hilo de reanudar. Esto es necesario para evitar que un subproceso termine antes de que el subproceso de inicio pueda grabar su identificador.

La mejor práctica es usar _beginthreadex, comenzar a suspender y luego reanudar después de grabar el identificador, esperar en el identificador está bien, CloseHandledebe llamarse


8

CreateThread()solía tener pérdidas de memoria cuando utiliza funciones CRT en su código. _beginthreadex()tiene los mismos parámetros que CreateThread()y es más versátil que _beginthread(). Así que te recomiendo que uses _beginthreadex().


2
Artículo de 1999, puede haber sido arreglado desde entonces
bobobobo

1
Este artículo de 2005 todavía confirma que hay un problema.
Jaywalker

2
Sí, solo se aplica a MSVC ++ 6.0 Service Pack 5 y versiones anteriores. (ver "Aplicable a" desplegable expandible). Esto no es un problema hoy si está utilizando VC7 o superior.
bobobobo

1
¡Esto sigue siendo un problema si vincula el CRT estático! También sigue siendo un problema si llama a DisableThreadLibraryCalls en una DLL que está estáticamente vinculada; vea mi artículo de KB: support.microsoft.com/kb/555563/en-us
Jochen Kalmbach

2
Usted tergiversado la información: CreateThreadno nunca perder memoria. Es más bien el CRT el que lo hace, cuando se llama desde un hilo que no se ha inicializado correctamente.
Inspeccionable el

6

Con respecto a su pregunta actualizada: "También he leído en un par de lugares a los que no puedo llamar WaitForSingleObject()si los usaba _beginthread(), pero si llamo _endthread()en el hilo, ¿no debería funcionar?"

En general, puede pasar un identificador de subproceso a WaitForSingleObject()(u otras API que esperan en los identificadores de objeto) para bloquear hasta que el subproceso se haya completado. Pero el identificador de subproceso creado por _beginthread()se cierra cuando _endthread()se llama (lo que se puede hacer explícitamente o implícitamente por el tiempo de ejecución cuando vuelve el procedimiento de subproceso).

El problema se menciona en la documentación para WaitForSingleObject():

Si este identificador está cerrado mientras la espera aún está pendiente, el comportamiento de la función no está definido.


5

En cuanto a las firmas de funciones, CreateThreades casi idéntico a _beginthreadex.

_beginthread,_beginthreadx vsCreateThread

HANDLE WINAPI CreateThread(
  __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
  __in       SIZE_T dwStackSize,
  __in       LPTHREAD_START_ROUTINE lpStartAddress,
  __in_opt   LPVOID lpParameter,
  __in       DWORD dwCreationFlags,
  __out_opt  LPDWORD lpThreadId
);

uintptr_t _beginthread( 
   void( *start_address )( void * ),
   unsigned stack_size,
   void *arglist 
);

uintptr_t _beginthreadex( 
   void *security,
   unsigned stack_size,
   unsigned ( *start_address )( void * ),
   void *arglist,
   unsigned initflag,
   unsigned *thrdaddr 
);

Los comentarios aquí indicados _beginthreadpueden usar una convención __cdeclo una __clrcallllamada como punto de inicio, y _beginthreadexpueden usar cualquiera __stdcallo __clrcallpara el punto de inicio.

Creo que cualquier comentario que la gente haya hecho sobre las pérdidas de memoria CreateThreadtiene más de una década y probablemente debería ignorarse.

Curiosamente, ambas _beginthread*funciones en realidad llaman CreateThreadbajo el capó, en C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\srcmi máquina.

// From ~line 180 of beginthreadex.c
/*
 * Create the new thread using the parameters supplied by the caller.
 */
if ( (thdl = (uintptr_t)
      CreateThread( (LPSECURITY_ATTRIBUTES)security,
                    stacksize,
                    _threadstartex,
                    (LPVOID)ptd,
                    createflag,
                    (LPDWORD)thrdaddr))
         == (uintptr_t)0 )
{
        err = GetLastError();
        goto error_return;
}

2
Comente, por qué no debe llamar a CreateThread y mezclar llamadas CRT en ese hilo (definitivamente no tiene una década de antigüedad, y definitivamente no debe ser ignorado) : "Si un hilo creado usando CreateThread llama al CRT, el CRT puede terminar el proceso en condiciones de poca memoria ".
Inspectable

3

beginthreadexte da un hilo HANDLEpara usar en WaitForSingleObjecty amigos. beginthreadno lo hace No olvides CloseHandle()cuando hayas terminado. La respuesta real sería usar boost::threado pronto la clase de hilo de C ++ 09.


La descripción de msdn dice que "si tiene éxito, cada una de estas funciones devuelve un identificador al subproceso recién creado"; refiriéndose a _beginthread () y _beginthreadex () ...
Kiril

@ Kiril: pero luego la documentación continúa diciendo que _beginthread cierra el identificador por usted, lo que significa que no puede usarlo si el hilo sale rápidamente ...
Roger Lipscombe

2

En comparación con _beginthread, con _beginthreadexusted puede:

  1. Especificar atributos de seguridad.
  2. Comience un hilo en estado suspendido.
  3. Puede obtener la identificación del hilo que se puede usar con OpenThread.
  4. Se garantiza que el identificador de hilo devuelto sea válido si la llamada fue exitosa. Hay que cerrar el asa con CloseHandle.
  5. El identificador de subproceso devuelto se puede usar con las API de sincronización.

El _beginthreadexse parece mucho CreateThread, pero el primero es una implementación de CRT y el segundo una llamada a la API de Windows. La documentación para CreateThread contiene la siguiente recomendación:

Un subproceso en un ejecutable que llama a la biblioteca de tiempo de ejecución C (CRT) debe usar las funciones _beginthreadexy _endthreadexpara la gestión de subprocesos en lugar de CreateThready ExitThread; Esto requiere el uso de la versión multiproceso del CRT. Si un subproceso creado utilizando CreateThreadllama a la CRT, la CRT puede finalizar el proceso en condiciones de poca memoria.


De acuerdo con la especificación API, los puntos de viñeta 3-5 no son exclusivos de _beginthreadex. Puede emitir el uintptr_tretorno de ambas funciones a HANDLE.
Andon M. Coleman

Sí, tienes razón en teoría. En la práctica, la diferencia es que _beginthreadcierra el tirador al salir. Por lo tanto, no puede usar el identificador de manera confiable con las API de sincronización o para obtener la identificación del subproceso hasta y a menos que use otra forma de sincronizar y duplicar el identificador. Pero entonces lo está _beginthreadexhaciendo por ti.
Vishal

2

CreateThread()una vez fue un no-no porque el CRT se inicializaría / limpiaría incorrectamente. Pero esto ahora es historia: ahora se puede (usando VS2010 y probablemente algunas versiones anteriores) llamar CreateThread()sin romper el CRT.

Aquí está la confirmación oficial de MS . Establece una excepción:

En realidad, la única función que no debe usarse en un hilo creado con CreateThread()es la signal()función.

Sin embargo, desde el punto de vista de la consistencia, personalmente prefiero seguir usando _beginthreadex().


Si bien supongo que esto es cierto, ¿puede proporcionar alguna evidencia autorizada, ya sea al vincular a la documentación de MS o al analizar las fuentes CRT _beginthreadex / _endthreadex?
Suma

@Suma, creo que agregué el enlace de MS mientras escribía su comentario ;-)
Serge Wautier

El documento al que se está vinculando no parece confirmar: "Sin embargo, dependiendo de cómo se llamen las funciones CRT, puede haber una pequeña pérdida de memoria cuando los subprocesos se terminan". Esto significa que ya no es un no-no grande y general, sino un no-no si está creando hilos con frecuencia y utilizando esas funciones en ellos. Sin embargo, el documento es de 2005 y, por lo tanto, no puede abordar el estado reciente del asunto.
Suma

1
Hmm ... aunque podría depender del caso de uso, una función que deja una pérdida de memoria, sin importar el tamaño, consideraría un no-no ... ¡en particular si hay una alternativa sin pérdida!
alk

"Ahora se puede llamar a CreateThread () sin romper el CRT". - Desafortunadamente, esto no es cierto, y nunca lo ha sido. From CreateThread : "Un subproceso en un ejecutable que llama a la biblioteca de tiempo de ejecución C (CRT) debe usar las funciones _beginthreadex y _endthreadex para la gestión de subprocesos [...] Si un subproceso creado usando CreateThread llama al CRT, el CRT puede terminar el proceso en condiciones de poca memoria ".
Inspectable

2

CreateThread()es la llamada a la API de Windows que es neutral al lenguaje. Simplemente crea un objeto OS - thread y devuelve HANDLE a este thread. Todas las aplicaciones de Windows están utilizando esta llamada para crear hilos. Todos los idiomas evitan las llamadas directas a la API por razones obvias: 1. No desea que su código sea específico del sistema operativo 2. Debe realizar algunas tareas de mantenimiento antes de llamar a API: convertir parámetros y resultados, asignar almacenamiento temporal, etc.

_beginthreadex()es la envoltura de C CreateThread()que da cuenta de C específica. Permite que los F-ns de un solo subproceso original funcionen en un entorno multiproceso al asignar almacenamiento específico de subproceso.

Si no usa CRT, no puede evitar una llamada directa CreateThread(). Si usa CRT, debe usar _beginthreadex()o algunas cadenas de CRT f-ns pueden no funcionar correctamente antes de VC2005.


1

CreateThread()es la llamada directa al sistema. Está implementado en el Kernel32.dllcual, muy probablemente, su aplicación ya estará vinculada por otras razones. Siempre está disponible en los sistemas modernos de Windows.

_beginthread()y _beginthreadex()son funciones de contenedor en Microsoft C Runtime ( msvcrt.dll). Las diferencias entre las dos llamadas se indican en la documentación. Por lo tanto, está disponible cuando Microsoft C Runtime está disponible, o si su aplicación está vinculada estáticamente con ella. Es probable que también se vincule con esa biblioteca, a menos que esté codificando en la API de Windows pura (como lo hago personalmente a menudo).

Su pregunta es coherente y en realidad recurrente. Como muchas API, hay una funcionalidad duplicada y ambigua en la API de Windows con la que tenemos que lidiar. Lo peor de todo, la documentación no aclara el problema. Supongo que la _beginthread()familia de funciones se creó para una mejor integración con otras funcionalidades C estándar, como la manipulación de errno. _beginthread()así se integra mejor con el tiempo de ejecución de C.

A pesar de eso, a menos que tenga buenas razones para usar _beginthread()o _beginthreadex(), debe usarlo CreateThread(), principalmente porque podría obtener una dependencia de biblioteca menos en su ejecutable final (y para MS CRT esto importa un poco). Tampoco tiene un código de ajuste alrededor de la llamada, aunque este efecto es insignificante. En otras palabras, creo que la razón principal para seguir CreateThread()es que no hay una buena razón _beginthreadex()para comenzar. Las funcionalidades son precisamente, o casi, las mismas.

Una buena razón para usar _beginthread() sería (ya que parece ser falso) que los objetos C ++ se desenrollarían / ​​destruirían adecuadamente si _endthread()se llamara.


No hay llamadas de función ambiguas en absoluto . CreateThreades la llamada a la API de Windows para crear un hilo. Si está utilizando el CRT (porque está programando en C o C ++), debe crear hilos utilizando las _beginthread[ex]llamadas del CRT (que llaman CreateThreadademás de realizar la inicialización del CRT necesaria). La diferencia más importante entre _beginthready la ex-variante: el primero conserva la propiedad del identificador de subproceso nativo, mientras que el segundo pasa la propiedad a la persona que llama.
Inspectable

Nitpick: nomsvcrt.dll es la DLL de tiempo de ejecución C! Ver blogs.msdn.microsoft.com/oldnewthing/20140411-00/?p=1273
Govind Parmar el

0

Las otras respuestas no discuten las implicaciones de llamar a una función de tiempo de ejecución C que envuelve una función API Win32. Esto es importante cuando se considera el comportamiento de bloqueo del cargador de DLL.

Ya sea que se _beginthread{ex}administre o no una gestión especial de memoria de fibra / hilo de tiempo de ejecución de C, como se analiza en las otras respuestas, se implementa en (suponiendo un enlace dinámico al tiempo de ejecución de C) una DLL que los procesos pueden no haberse cargado todavía.

No es seguro llamar _beginthread*desde DllMain. He probado esto escribiendo una DLL cargada usando la función "AppInit_DLLs" de Windows. Llamar en _beginthreadex (...)lugar de CreateThread (...)provocar que MUCHAS partes importantes de Windows dejen de funcionar durante el arranque como los DllMainpuntos muertos de punto de entrada que esperan que se libere el bloqueo del cargador para realizar ciertas tareas de inicialización.

Por cierto, esta es también la razón por la que kernel32.dll tiene muchas funciones de cadena superpuestas que también tiene el tiempo de ejecución de C: úselas DllMainpara evitar el mismo tipo de situación.


0

Si lees el libro Depuración de aplicaciones de Windows de Jeffrey Richter, explica que casi en todos los casos debes llamar en _beginthreadexlugar de llamar CreateThread. _beginthreades solo un contenedor simplificado _beginthreadex.

_beginthreadexinicializa ciertas partes internas de CRT (C RunTime) que la CreateThreadAPI no haría.

Una consecuencia si usa la CreateThreadAPI en lugar de usar _begingthreadexllamadas a funciones CRT podría causar problemas inesperados.

Echa un vistazo a este viejo Microsoft Journal de Richter.


-2

Ya no hay diferencia entre los dos.

Todos los comentarios sobre pérdidas de memoria, etc. se basan en versiones muy antiguas de <VS2005. He hecho algunas pruebas de estrés hace años y podría desacreditar este mito. Incluso Microsoft mezcla los estilos en sus ejemplos, casi nunca usa _beginthread.


CreateThread : "Si un hilo creado usando CreateThread llama al CRT, el CRT puede terminar el proceso en condiciones de poca memoria".
Inspectable

Basado en la subsecuencia "requiere el uso de la versión multiproceso del CRT", supongo que esto es basura de documentación ya que ya no existe una versión CRT multiproceso y desde hace muchos años.
Lothar

"ya no hay una versión de CRT multiproceso" : el MSDN afirma que "[l] a CRT de un solo subproceso ya no está disponible". Ambos no pueden tener razón. Iré con el MSDN aquí también.
Inspectable

Fue un error tipográfico, por supuesto, quise decir que el subproceso único se ha ido y el multiproceso se ha convertido en el estándar y lo que se ha ido es la distinción entre usar o no usar hilos.
Lothar

Esto realmente se está volviendo extraño. Ahora está utilizando una declaración, sin duda es correcta ( "requiere el uso de la versión multiproceso de la CRT" ) para afirmar que tanto esta declaración como el resto de la documentación es muy probable que sea incorrecta. Eso seguro no suena bien.
Inspectable
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.