_beginthread, _beginthreadex
Crea un subproceso.
Importante |
---|
Esta API no se puede utilizar en las aplicaciones que se ejecutan en tiempo de ejecución de Windows.Para obtener más información, vea Funciones CRT no compatibles con /ZW. |
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthread( // MANAGED CODE
void( __clrcall *start_address )( void * ),
unsigned stack_size,
void *arglist
);
uintptr_t _beginthreadex( // NATIVE CODE
void *security,
unsigned stack_size,
unsigned ( __stdcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
uintptr_t _beginthreadex( // MANAGED CODE
void *security,
unsigned stack_size,
unsigned ( __clrcall *start_address )( void * ),
void *arglist,
unsigned initflag,
unsigned *thrdaddr
);
Parámetros
start_address
Dirección de inicio de una rutina que comienza la ejecución de un nuevo subproceso.Para _beginthread, la convención de llamada es __cdecl (para código nativo) o __clrcall (para código administrado); para _beginthreadex, es __stdcall (para código nativo) o __clrcall (para código administrado).stack_size
Tamaño de la pila para un nuevo subproceso o 0.Arglist
Lista de argumentos que se va a pasar a un nuevo subproceso o un valor NULL.Security
Puntero a una estructura de SECURITY_ATTRIBUTES que determina si el identificador devuelto se puede heredar de procesos secundarios.Si NULL, el identificador no puede heredarse.Debe ser NULL para las aplicaciones de Windows 95.Initflag
Estado inicial de un nuevo subproceso (0 para ejecutar o de CREATE_SUSPENDED para suspendido); uso ResumeThread de ejecutar el subproceso.Thrdaddr
Señala a una variable de 32 bits que recibe el identificador del subproceso.Podría ser NULL, en cuyo caso no se utiliza.
Valor devuelto
Si es correcto, cada una de estas funciones devuelve un identificador al subproceso creado recientemente; sin embargo, si el subproceso sale recién creado demasiado rápidamente, _beginthread no puede devolver un identificador válido (consulte la explicación en la sección de Remarks )._beginthread devuelve -1L en un error, en este caso errno se establece en EAGAIN si hay demasiados subprocesos, a EINVAL si el argumento no es válido o el tamaño de pila es incorrecto, o a EACCES en el caso de recursos insuficientes (como memoria)._beginthreadex devuelve 0 en un error, en cuyo caso se establecen errno y _doserrno.
Si startaddress es NULL, se invoca el controlador no válido de parámetro, tal y como se describe en Validación de parámetros.Si la ejecución puede continuar, este errno establecido funciones a EINVAL y retorno -1.
Para obtener más información sobre éstos y otros códigos de retorno, vea _doserrno, errno, _sys_errlist, y _sys_nerr.
Para obtener más información sobre uintptr_t, vea Tipos estándar.
Comentarios
La función de _beginthread crea un subproceso que comience la ejecución de una rutina en start_address.La rutina en start_address debe utilizar __cdecl (para código nativo) o la convención de llamada de __clrcall (para código administrado) y no debe tener ningún valor devuelto.Cuando el subproceso vuelve de la rutina, finaliza automáticamente.Para obtener más información sobre los subprocesos, vea Multithreading.
_beginthreadex se parece a Win32 CreateThread API más estrechamente que hace _beginthread._beginthreadex diferencia de _beginthread de las maneras siguientes:
_beginthreadex tiene tres parámetros adicionales: initflag, security, y threadaddr.El nuevo subproceso se puede crear en un estado suspendido, con una seguridad especificada (Windows NT sólo), y se puede lograr utilizando thrdaddr, que es el identificador del subproceso.
La rutina en start_address pasó a _beginthreadex debe utilizar __stdcall (para código nativo) o la convención de llamada de __clrcall (para código administrado) y debe devolver un código de salida del subproceso.
_beginthreadex devuelve 0 en el error, en lugar de -1L.
Un subproceso creado con _beginthreadex termina con una llamada a _endthreadex.
Hace la función de _beginthreadex le ofrece más control sobre cómo se crea el subproceso que _beginthread.La función de _endthreadex también es más flexible.Por ejemplo, con _beginthreadex, puede usar la información de seguridad, establecer el estado inicial del subproceso (ejecutándose o suspendido), y obtener el identificador de subproceso del subproceso creado recientemente.También puede utilizar el identificador de subproceso devuelto por _beginthreadex con la sincronización API, que se pueden realizar con _beginthread.
Es más seguro utilizar _beginthreadex que _beginthread.Si el subproceso sale generado por _beginthread rápidamente, el identificador devuelto al llamador de _beginthread podría ser válido o, peor, elija otro subproceso.Sin embargo, el identificador devuelto por _beginthreadex tiene que cerrar el llamador de _beginthreadex, por lo que se garantiza que sea un identificador válido si _beginthreadex no devuelve un error.
Puede llamar a _endthread o _endthreadex explícitamente para terminar el subproceso; sin embargo, _endthread o _endthreadex se llama automáticamente al subproceso vuelve de la rutina pasa como parámetro.Terminar un subproceso con una llamada a endthread o a _endthreadex ayuda a garantizar una recuperación correcta de los recursos asignados para el subproceso.
_endthread automáticamente cierra el identificador del subproceso (aunque no hace _endthreadex ).Por consiguiente, cuando utilice _beginthread y _endthread, no cierre el identificador de subproceso llamando a Win32 CloseHandle API.Este comportamiento difiere de Win32 ExitThread API.
[!NOTA]
Para un archivo ejecutable vinculado con Libcmt.lib, no llame a Win32 ExitThread API; esto evita que el sistema en tiempo de ejecución reclama recursos asignados._endthread y recuperación de _endthreadex asignaron recursos de subproceso y después llama a ExitThread.
Los identificadores del sistema operativo la asignación de la pila cuando se llama a _beginthread o _beginthreadex; no necesita pasar la dirección de la pila del subproceso cualquiera de estas funciones.Además, el argumento de stack_size puede ser 0, en cuyo caso el sistema operativo utiliza el mismo valor que la pila especificada del subproceso principal.
arglist es un parámetro que se pasará al subproceso recién creado.Normalmente es la dirección de un elemento de datos, como una cadena de caracteres.arglist puede ser NULL si no es necesario, pero _beginthread y _beginthreadex deben proporcionar un valor al paso al nuevo subproceso.Se terminan todos los subprocesos si cualquier subproceso llama abort, exit, _exit, o ExitProcess.
La configuración regional del nuevo subproceso se hereda del subproceso primario.Si el subproceso la configuración regional está habilitada por una llamada a _configthreadlocale (o global o para nuevos subprocesos sólo), el subproceso puede cambiar su configuración regional independientemente de su elemento primario llamando a setlocale o _wsetlocale.Para obtener más información, vea Configuración regional.
Para el código mixto como puro, _beginthread y _beginthreadex ambos tienen dos sobrecargas, una tomando un puntero a función nativa de la convención de llamada, otra con un puntero a función de __clrcall.La primera sobrecarga no es una dominio- segura y nunca no estará.Si se escribe se mezclan o código puro que debe asegurarse de que el nuevo subproceso escriba el dominio de aplicación correcto antes de tener acceso a recursos administrados.Puede hacerlo, por ejemplo, utilizando call_in_appdomain (Función).La segunda sobrecarga es una dominio- segura; el subproceso recién creado finalizará siempre en el dominio de aplicación del llamador de _beginthread o de _beginthreadex.
Requisitos
Rutina |
Encabezado necesario |
---|---|
_beginthread |
<process.h> |
_beginthreadex |
<process.h> |
Para obtener más información de compatibilidad, vea Compatibilidad en la Introducción.
Bibliotecas
Versiones multiproceso de Bibliotecas en tiempo de ejecución de C.
Para utilizar _beginthread o _beginthreadex, la aplicación debe vincularse a una de las bibliotecas en tiempo de ejecución multiproceso de C.
Ejemplo
El ejemplo siguiente utiliza _beginthread y _endthread.
// crt_BEGTHRD.C
// compile with: /MT /D "_X86_" /c
// processor: x86
#include <windows.h>
#include <process.h> /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>
void Bounce( void *ch );
void CheckKey( void *dummy );
/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))
BOOL repeat = TRUE; /* Global repeat flag and video variable */
HANDLE hStdOut; /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* Console information structure */
int main()
{
CHAR ch = 'A';
hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
/* Get display screen's text row and column information. */
GetConsoleScreenBufferInfo( hStdOut, &csbi );
/* Launch CheckKey thread to check for terminating keystroke. */
_beginthread( CheckKey, 0, NULL );
/* Loop until CheckKey terminates program. */
while( repeat )
{
/* On first loops, launch character threads. */
_beginthread( Bounce, 0, (void *) (ch++) );
/* Wait one second between loops. */
Sleep( 1000L );
}
}
/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
_getch();
repeat = 0; /* _endthread implied */
}
/* Bounce - Thread to create and and control a colored letter that moves
* around on the screen.
* Params: ch - the letter to be moved
*/
void Bounce( void *ch )
{
/* Generate letter and color attribute from thread argument. */
char blankcell = 0x20;
char blockcell = (char) ch;
BOOL first = TRUE;
COORD oldcoord, newcoord;
DWORD result;
/* Seed random number generator and get initial location. */
srand( _threadid );
newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
while( repeat )
{
/* Pause between loops. */
Sleep( 100L );
/* Blank out our old position on the screen, and draw new letter. */
if( first )
first = FALSE;
else
WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );
/* Increment the coordinate for next placement of the block. */
oldcoord.X = newcoord.X;
oldcoord.Y = newcoord.Y;
newcoord.X += GetRandom( -1, 1 );
newcoord.Y += GetRandom( -1, 1 );
/* Correct placement (and beep) if about to go off the screen. */
if( newcoord.X < 0 )
newcoord.X = 1;
else if( newcoord.X == csbi.dwSize.X )
newcoord.X = csbi.dwSize.X - 2;
else if( newcoord.Y < 0 )
newcoord.Y = 1;
else if( newcoord.Y == csbi.dwSize.Y )
newcoord.Y = csbi.dwSize.Y - 2;
/* If not at a screen border, continue, otherwise beep. */
else
continue;
Beep( ((char) ch - 'A') * 100, 175 );
}
/* _endthread given to terminate */
_endthread();
}
presione cualquier tecla para final
El ejemplo siguiente muestra cómo puede utilizar el identificador de subproceso devuelto por _beginthreadex con la sincronización API WaitForSingleObject.El subproceso principal espera el segundo subproceso finalice antes de continuar.Cuando el segundo subproceso llama _endthreadex, hace el objeto de subproceso para ir al estado señalado.Esto permite que el subproceso principal continúa ejecutándose.Esto no se puede hacer con _beginthread y _endthread, porque _endthread llama CloseHandle, destruyendo el objeto de subproceso antes de poder establecida en el estado señalado.
// crt_begthrdex.cpp
// compile with: /MT
#include <windows.h>
#include <stdio.h>
#include <process.h>
unsigned Counter;
unsigned __stdcall SecondThreadFunc( void* pArguments )
{
printf( "In second thread...\n" );
while ( Counter < 1000000 )
Counter++;
_endthreadex( 0 );
return 0;
}
int main()
{
HANDLE hThread;
unsigned threadID;
printf( "Creating second thread...\n" );
// Create the second thread.
hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );
// Wait until second thread terminates. If you comment out the line
// below, Counter will not be correct because the thread has not
// terminated, and Counter most likely has not been incremented to
// 1000000 yet.
WaitForSingleObject( hThread, INFINITE );
printf( "Counter should be 1000000; it is-> %d\n", Counter );
// Destroy the thread object.
CloseHandle( hThread );
}
Equivalente en .NET Framework
System::Threading::Thread::Start