Aplicaciones Multi-Threads-I Ernesto Cuadros-Vargas ecuadros@spc.org.pe Sociedad Peruana de Computación Perú
Organización de la presentación Conceptos Básicos; Operaciones con hebras; Tipos de hebras; Comunicación entre hebras; Fibras; Otros puntos importantes; DEMOS; Sugerencias y conclusiones. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Conceptos básicos programa programa = algoritmos + ED; proceso abstracción de un programa en ejecución; hebras o threads secuencia de ejecución de un proceso; Aplicaciones Multi-Hebras
Programa-Proceso-Hebra Memoria Aplicaciones Multi-Hebras 011011111010 cargador
Programación Multi-Threads crear programas capaces de ejecutar más de una tarea en paralelo; las hebras pueden estar en el mismo proceso; estamos preparados para aprovechar mas de un procesador. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Origen de las hebras Proceso 1 Aplicaciones Multi-Hebras Tiempo
Origen de las hebras (cont) Aplicaciones Multi-Hebras P1 P2 Tiempo
Aplicaciones Multi-Hebras Algunos ejemplos manejadores de Bases de Datos; servidores de Web; servidores de FTP; grabación en segundo plano (ej. Word); compilación sin parar la edición, etc; nuestra vida diaria (trabajo en grupo, tareas en paralelo). Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Evolución sistemas monotareas vs. sistemas multitasking programas ST vs programas MT Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Ventajas mayor aprovechamiento de la capacidad ociosa del procesador; podemos aprovechar mas de un procesador; mayor paralelismo; menor tiempo de respuesta que en forma secuencial, etc. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Desventajas mayor complejidad; mayor cantidad de recursos necesarios (memoria, etc); política de planificación de procesos. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Cuándo usar MT ? cuando mi programa presenta bloques independientes; cuando tengo una pérdida de tiempo considerable por operaciones de I/O; NÚMERO DE PROCESADORES. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Transicion de ST a MT las hebras de ejecutan independientes unas de las otras Problemas ! sincronización en el mismo proceso (sibling Threads); en procesos diferentes. Aplicaciones Multi-Hebras
Planificador de procesos (Scheduler) Aplicaciones Multi-Hebras Corriendo (Running) 1 3 2 Bloqueado (Blocked) Listos (Ready) 4
Scheduler para 2 procesadores Aplicaciones Multi-Hebras Corriendo (Running) Bloqueado (Blocked) Listos (Ready) P2 P1 P5 P7 P6 P4
Aplicaciones Multi-Hebras Proceso vs Hebra una pila (Stack); entrada en el Scheduler; registros de la CPU; program counter, etc. archivos abiertos; variables globales; memoria asignada dinamicamente, etc. Aplicaciones Multi-Hebras
Necesidad de Sincronización Aplicaciones Multi-Hebras Ejemplos utilizando en la plataforma Win32
Problemas relacionados a la programación MT Atomicidad; Exclusión mutua: pedir un recurso, liberar el recurso Race Conditions: Un bug que depende del orden en el que se ejecuten dos o más tareas independientes Aplicaciones Multi-Hebras
Atomicidad y exclusión mutua Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Atomicidad (cont) Aplicaciones Multi-Hebras HANDLE hIOMutex= ::CreateMutex (NULL, FALSE, 0); // Pedir acceso al recurso ::WaitForSingleObject( hIOMutex, INFINITE ); // Realizar nuestra operación crítica ::fseek( fp, desired_position, 0L ); ::fwrite( data, sizeof( data ), 1, fp ); // Liberar el acceso al recurso ::ReleaseMutex(hIOMutex);
Aplicaciones Multi-Hebras Race Conditions Aplicaciones Multi-Hebras
Problemas relacionados a programación MT (cont) Deadlock; Diseño de clases seguras para ambientes MT; Starvation (morir de hambre) Threads de prioridades altas siempre ganaran el procesador. Aplicaciones Multi-Hebras
Deadlock (bloqueo mutuo) Aplicaciones Multi-Hebras
Clases seguras para ambientes MT void MyClass::PrintPersonalInfo() { m_report = Datos_Personales; Imprimir(); } void MyClass::PrintHistorico() { m_report = Historico; Imprimir(); } Aplicaciones Multi-Hebras Thread1 Thread2 void MyClass::Imprimir() { switch(m_report) { case Datos_Personales: …… break; case Datos_Personales: …… break; } }
Mecanismos de Sincronización por la cantidad de estados: binarios, de múltiples estados. por su alcance: dentro del mismo proceso, entre procesos. Aplicaciones Multi-Hebras
Por la cantidad de estados binarios Events (CEvent), CriticalSection (CCriticalSection), Mutex (CMutex). de múltiples estados: Semáforos (CSemaphore) Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Por su alcance dentro del mismo proceso: CriticalSection entre procesos: Event, Mutex, Semáforos, también sirven en el mismo proceso. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Entre procesos Aplicaciones Multi-Hebras Semáforo “Impresion” Handle(7) Semáforo “Impresion” Handle(35) Proceso 1 Proceso 2 Win32 Semaphore “Impresion” Kernel Object Usage Counter=2 More information ….
Aplicaciones Multi-Hebras Tipos de hebras worker threads o hebras trabajadoras; hebras con interface de usuario. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Worker Thread para tareas en background o en segundo plano; cuando no necesitamos enviar o recibir mensajes a través de ventanas; no es necesario interactuar con la hebra. Aplicaciones Multi-Hebras
Pasos para crear una Worker Thread programar una función que será al “main” de la hebra, crear la hebra propiamente dicha con alguna de las funciones API (CreateThread, _beginthread) Aplicaciones Multi-Hebras
Paso 1: Programar una función que será el “main” de la hebra DWORD WINAPI MyThreadMain(LPVOID lpParameter) { CStudent *pMyObj = (CStudent *)lpParameter; pMyObj->MyMethod1(); pMyObj->MyMethod2(); . return 0L; } Aplicaciones Multi-Hebras
Paso 2: Creación de una Thread con CreateThread HANDLE CreateThread( // puntero a los atributos de securidad LPSECURITY_ATTRIBUTES lpThreadAttributes, // Tamaño inicial del Stack para esta hebra DWORD dwStackSize, // puntero a la función de la hebra LPTHREAD_START_ROUTINE lpStartAddress, // argumento para la nueva hebra LPVOID lpParameter, // atributos de creación DWORD dwCreationFlags, // puntero para recibir el ID de la hebra LPDWORD lpThreadId ); Aplicaciones Multi-Hebras
Paso 2: Creación de una Thread con CreateThread (cont) CStudent *pMyObj = new CStudent; DWORD ThreadID; HANDLE myhandle = CreateThread( NULL, 4096, &MyThreadMain, (LPVOID)pMyObj, 0, // CREATE_SUSPENDED &ThreadId ); Aplicaciones Multi-Hebras
Hebras usando C Run-Time Library void __cdecl MyThreadMain2(void *lpParameter) { CStudent *pMyObj = (CStudent *)lpParameter; pMyObj->MyMethod1(); pMyObj->MyMethod2(); . return 0L; } Aplicaciones Multi-Hebras
Paso 2: Creación de una Thread con _beginthread (cont) unsigned long _beginthread( // Puntero a la funcion que controlará la hebra void( __cdecl *start_address )( void * ), // Tamaño del stack unsigned stack_size, // Lista de argumentos void *arglist ); HANDLE handle = (HANDLE)_beginthread( & MyThreadMain2, 4096, NULL); Aplicaciones Multi-Hebras
Operaciones básicas con una hebra ::WaitForSingleObject(hThread, 5); ::WaitForSingleObject(hThread, INFINITE); ::SuspendThread(hThread); ::ResumeThread(hThread); Aplicaciones Multi-Hebras
Prioridades de una Thread (SetThreadPriority) ::SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); THREAD_PRIORITY_ABOVE_NORMAL; THREAD_PRIORITY_BELOW_NORMAL; THREAD_PRIORITY_HIGHEST; THREAD_PRIORITY_IDLE; THREAD_PRIORITY_LOWEST; THREAD_PRIORITY_NORMAL; THREAD_PRIORITY_TIME_CRITICAL. Aplicaciones Multi-Hebras
Prioridades para todo el proceso ::SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); HIGH_PRIORITY_CLASS; IDLE_PRIORITY_CLASS; NORMAL_PRIORITY_CLASS; REALTIME_PRIORITY_CLASS. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Demo Worker Threads Break !
Aplicaciones Multi-Threads-II Ernesto Cuadros-Vargas ecuadros@spc.org.pe Sociedad Peruana de Computación Piura-Perú
Aplicaciones Multi-Hebras Hebras con interface útiles cuando necesitamos enviar mensajes o interactuar a través de algún mecanismo visible al usuario (generalmente una ventana) existe la clase CWinThread (MFC) Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Secuencia de creación crear la clase heredada de CWinThread (inicialmente esta vacía); BOOL CMyThread::InitInstance() { return TRUE; } crear la hebra hija; Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Crear la hebra hija void CMainFrame::OnNuevaThread() { // TODO: Add your command handler code here CRuntimeClass *pRuntimeClass = RUNTIME_CLASS(CMyThread); CMyThread *pMyThread = (CMyThread *)pRuntimeClass->CreateObject(); pMyThread->CreateThread(); } Aplicaciones Multi-Hebras
Crear la hebra hija (cont) BOOL CMyThread::InitInstance() { CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CTeste2Doc), // clase del documento RUNTIME_CLASS(CMainFrame), // clase del MainFrame RUNTIME_CLASS(CTeste2View)); // clase del área de cliente // Crear un nuevo documento para esta ventana CDocument *pDoc = pDocTemplate->CreateNewDocument(); // Crear la ventana propiamente dicha m_pMainWnd = pDocTemplate->CreateNewFrame(pDoc, NULL); // Hacerla visible m_pMainWnd->ShowWindow(SW_SHOW); // Enviarle un mensage de actualizacion m_pMainWnd->UpdateWindow(); return TRUE; } Aplicaciones Multi-Hebras
Comunicación entre ventanas y/o hebras colas de mensajes de tamaño fijo en Win16 dinámicas en Win32 (listas enlazadas) SendMessage PostMessage PostThreadMessage SendMessageTimeout Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras PostMessage PostMessage(HWND hWnd, UINT msg, WPARAM, LPARAM); coloca el mensaje en la fila de la hebra que creó hWnd y retorna. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras SendMessage SendMessage(HWND hWnd, UINT msg, WPARAM, LPARAM) coloca el mensaje en la fila de la hebra que creó hWnd espera hasta que el mensaje sea procesado retorna Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras PostThreadMessage PostThreadMessage(DWORD ThreadID, UINT msg, WPARAM, LPARAM) coloca el mensaje en la fila de la hebra identificada con ThreadID retorna Aplicaciones Multi-Hebras
Importante: SendMessage (entre ventanas) una ventana procesa sus mensajes cuando la hebra que la creo esta activa! un mensaje siempre va a la cola de mensajes de la hebra que la creó. Aplicaciones Multi-Hebras
Creando una función para recibir mensajes LRESULT CMyThread::MyFuncion( LPARAM wParam, LPARAM lParam) { // Aqui debemos agregar nuestro código return 0L; } Aplicaciones Multi-Hebras
Mapeando un mensaje a una función en la clase heredada de CWinThread BEGIN_MESSAGE_MAP(CMyThread, CWinThread) //{{AFX_MSG_MAP(CMyThread) ON_THREAD_MESSAGE(WM_MYMESSAGE, MyFuncion) //}}AFX_MSG_MAP END_MESSAGE_MAP() // #define WM_MYMESSAGE (WM_USER+1) ……. LRESULT CMyThread::MyFuncion( LPARAM wParam, LPARAM lParam) { // Aqui debemos agregar nuestro código return 0L; } Aplicaciones Multi-Hebras
Mapeando un mensaje a una función de una ventana BEGIN_MESSAGE_MAP(CMyEdit, CEdit) //{{AFX_MSG_MAP(CMyThread) ON_THREAD_MESSAGE(WM_MYMESSAGE, MyFuncion) //}}AFX_MSG_MAP END_MESSAGE_MAP() // #define WM_MYMESSAGE (WM_USER+1) ……. LRESULT CMyThread::MyFuncion( LPARAM wParam, LPARAM lParam) { // Aqui debemos agregar nuestro código return 0L; } Aplicaciones Multi-Hebras
Comunicación entre ventanas y/o hebras (cont) SendMessageCallback VOID CALLBACK SendMessageCallback( HWND hWnd, UINT uMsg, DWORD dwData, LRESULT lResult); Aplicaciones Multi-Hebras
Comunicación entre ventanas y/o hebras (cont) SendNotifyMessage coloca el mensaje en la cabeza de la lista de la otra hebra y retorna; si esta en la misma hebra se comporta igual que SendMessage. MsgWaitForMultipleObjects espera por mensajes en su propia fila de mensajes. Aplicaciones Multi-Hebras
Otras formas de comunicación Memoria Compartida (Shared Memory), Archivos Mapeados a memoria (Memory Mapped Files), Tubos Anónimos (Anonymous Pipes), Aplicaciones Multi-Hebras
Memoria Compartida (Shared Memory & Memory Mapped Files) crear el archivo (CreateFile, OpenFile) CreateFileMapping MapViewOfFile Aplicaciones Multi-Hebras
Memoria Compartida (Shared Memory & Memory Mapped Files) HANDLE hFile, hMapping; LPVOID lpBaseAddress; // mapear el archivo … hFile = CreateFile( "somefile.dat", ...); hMapping = CreateFileMapping( hFile, ...); lpBaseAddress = MapViewOfFile( hMapping, ...); // MapViewOfFile incrementó los contadores de uso de los objetos… CloseHandle(hFile); CloseHandle(hMapping); // usar lpBaseAddress aquí ... UnmapViewOfFile(lpBaseAddress); // decrementa los contadores de uso de hFile y hMapping // destruyéndolos DEMO Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Tubos (Pipes) tubos bidireccionales para pasar datos, anónimos (Win95, WinNT, etc) named Pipes (sólo se pueden crear desde WinNT, pero pueden ser abiertos desde Win95) remotamente \\.\pipe\mi-nuevo-pipe Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Tubos (Pipes) (cont) poseen dos conductos Lectura, Escritura envío de datos: First In First Out (FIFO) Aplicaciones Multi-Hebras
Tubos Anónimos (Anonymous Pipes) BOOL CreatePipe( // pointer to read handle PHANDLE hReadPipe, // pointer to write handle PHANDLE hWritePipe, // pointer to security attributes LPSECURITY_ATTRIBUTES lpPipeAttributes, // pipe size DWORD nSize); Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Fibras unidad de ejecución que puede ser manualmente activada por la aplicaciones; el usuario puede decidir cuando darle el procesador a otra fibra; corren en el contexto de una hebra; una hebra puede controlar múltiples fibras. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Fibras (cont) en general no ofrecen ventajas sin son comparadas con una aplicación Multi- hebras bien diseñada; mejor aprender a controlas bien las hebras. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Fibras (cont) ConvertThreadToFiber CreateFiber DeleteFiber GetCurrentFiber GetFiberData SwitchToFiber Aplicaciones Multi-Hebras
Otros puntos importantes MCL (Multithreading Class Library); depuración de hebras; ningún depurador substituye un buen diseño previo. Aplicaciones Multi-Hebras
Experimentos: El problema de los filósofos Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Experimentos: Proyecto Informedia-CMU Fastmap ST vs. Fastmap MT (2-CPUs) Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Sugerencias la naturaleza del problema; atomicidad del código (el Scheduler podría parar la ejecución); estados de espera óptimos; cantidad de hebras. Aplicaciones Multi-Hebras
Aplicaciones Multi-Hebras Conclusiones depende de la naturaleza del problema mas que del tipo de máquina, los programas MT pueden correr con una CPU pero están preparados para trabajar con mas CPU, el número de hebras está vinculado al número de procesadores y a la cantidad de operaciones con I/O. Aplicaciones Multi-Hebras
GRACIAS ! Ernesto Cuadros-Vargas Sociedad Peruana de Computación Aplicaciones Multi-Hebras Ernesto Cuadros-Vargas Sociedad Peruana de Computación http://socios.spc.org.pe/ecuadros/ ecuadros@spc.org.pe