Compartir a través de


Tutorial: Adaptar el código existente para usar tareas ligeras

En este tema se muestra cómo adaptar código existente que usa la API de Windows para crear y ejecutar un subproceso para una tarea ligera.

Una tarea ligera es aquella que se programa directamente a partir de un objeto concurrency::Scheduler o concurrency::ScheduleGroup. Las tareas ligeras son útiles cuando se adapta código existente para usar la funcionalidad de programación del Runtime de simultaneidad.

Requisitos previos

Antes de empezar este tutorial, lea el tema Programador de tareas.

Ejemplo

En el siguiente ejemplo se muestra el uso típico de la API de Windows para crear y ejecutar un subproceso. En este ejemplo se usa la función CreateThread para llamar a MyThreadFunction en un subproceso independiente.

Código inicial

// windows-threads.cpp
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#define BUF_SIZE 255

DWORD WINAPI MyThreadFunction(LPVOID param);

// Data structure for threads to use.
typedef struct MyData {
    int val1;
    int val2;
} MYDATA, *PMYDATA;

int _tmain()
{
   // Allocate memory for thread data.
   PMYDATA pData = (PMYDATA) HeapAlloc(GetProcessHeap(), 
      HEAP_ZERO_MEMORY, sizeof(MYDATA));

   if( pData == NULL )
   {
      ExitProcess(2);
   }

   // Set the values of the thread data.
   pData->val1 = 50;
   pData->val2 = 100;

   // Create the thread to begin execution on its own.
   DWORD dwThreadId;
   HANDLE hThread = CreateThread( 
      NULL,                   // default security attributes
      0,                      // use default stack size  
      MyThreadFunction,       // thread function name
      pData,                  // argument to thread function 
      0,                      // use default creation flags 
      &dwThreadId);           // returns the thread identifier 

   if (hThread == NULL) 
   {      
      ExitProcess(3);
   }

   // Wait for the thread to finish.
   WaitForSingleObject(hThread, INFINITE);

   // Close the thread handle and free memory allocation.
   CloseHandle(hThread);
   HeapFree(GetProcessHeap(), 0, pData);

   return 0;
}

DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
   PMYDATA pData = (PMYDATA)lpParam;

   // Use thread-safe functions to print the parameter values.

   TCHAR msgBuf[BUF_SIZE];
   StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"), 
     pData->val1, pData->val2); 

   size_t cchStringSize;
   StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);

   DWORD dwChars;
   WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msgBuf, (DWORD)cchStringSize, &dwChars, NULL);

   return 0;
}

Este ejemplo produce el siguiente resultado:

Parameters = 50, 100

Los siguientes pasos muestran cómo adaptar el ejemplo de código para usar el Runtime de simultaneidad para realizar la misma tarea.

Para adaptar el ejemplo para usar una tarea ligera

  1. Agregue una directiva #include para el archivo de encabezado concrt.h.
#include <concrt.h>
  1. Agregue una directiva using para el espacio de nombres concurrency.
using namespace concurrency;
  1. Cambie la declaración de MyThreadFunction pasa usar la convención de llamada __cdecl y devolver void.
void __cdecl MyThreadFunction(LPVOID param);
  1. Modifique la estructura de MyData para incluir un objeto concurrency::event que indique a la aplicación principal que la tarea ha terminado.
typedef struct MyData {
    int val1;
    int val2;
    event signal;
} MYDATA, *PMYDATA;
  1. Reemplace la llamada a CreateThread por una llamada al método concurrency::CurrentScheduler::ScheduleTask.
CurrentScheduler::ScheduleTask(MyThreadFunction, pData);
  1. Reemplace la llamada a WaitForSingleObject por una llamada al método concurrency::event::wait para esperar a que finalice la tarea.
// Wait for the task to finish.
pData->signal.wait();
  1. Quite la llamada a CloseHandle.

  2. Cambie la signatura de la definición de MyThreadFunction para que coincida con el paso 3.

void __cdecl MyThreadFunction(LPVOID lpParam)
  1. Al final de la función MyThreadFunction, llame al método concurrency::event::set para indicar a la aplicación principal que la tarea ha terminado.
pData->signal.set();
  1. Quite la instrucción return de MyThreadFunction.

Código completo

En el siguiente ejemplo completo se muestra código que usa una tarea ligera para llamar a la función MyThreadFunction.

// migration-lwt.cpp
// compile with: /EHsc
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <concrt.h>

using namespace concurrency;

#define BUF_SIZE 255

void __cdecl MyThreadFunction(LPVOID param);

// Data structure for threads to use.
typedef struct MyData {
    int val1;
    int val2;
    event signal;
} MYDATA, *PMYDATA;

int _tmain()
{
   // Allocate memory for thread data.
   PMYDATA pData = (PMYDATA) HeapAlloc(GetProcessHeap(), 
      HEAP_ZERO_MEMORY, sizeof(MYDATA));

   if( pData == NULL )
   {
      ExitProcess(2);
   }

   // Set the values of the thread data.
   pData->val1 = 50;
   pData->val2 = 100;

   // Create the thread to begin execution on its own.
   CurrentScheduler::ScheduleTask(MyThreadFunction, pData);

   // Wait for the task to finish.
   pData->signal.wait();

   // Free memory allocation.
   HeapFree(GetProcessHeap(), 0, pData);

   return 0;
}

void __cdecl MyThreadFunction(LPVOID lpParam)
{
   PMYDATA pData = (PMYDATA)lpParam;

   // Use thread-safe functions to print the parameter values.

   TCHAR msgBuf[BUF_SIZE];
   StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"), 
     pData->val1, pData->val2); 

   size_t cchStringSize;
   StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);

   DWORD dwChars;
   WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), msgBuf, (DWORD)cchStringSize, &dwChars, NULL);

   pData->signal.set();
}

Consulte también

Programador de tareas
Scheduler (clase)