sessão 6 – Memória partilhada / Sincronização – II Memória partilhada e Semáforos
Bibliografia de apoio:
Capítulos 5, 6, 7 e 8 do Livro Windows System Programming (da bibliografia) (149-155, 194-195, 230-231, 285-287)
MSDN:
Synchronization Objects https://docs.microsoft.com/pt-pt/windows/win32/sync/synchronization-objects
Synchronization Objects (inclui semáforos) https://docs.microsoft.com/pt-pt/windows/win32/sync/synchronization-objects
Wait Functions https://msdn.microsoft.com/en-us/library/windows/desktop/ms687069(v=vs.85).aspx
Time Functions https://docs.microsoft.com/en-us/windows/win32/sysinfo/time-functions
Named Shared Memory https://docs.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory
A memória partilhada entre diferentes processos, e é controlado através de um Mutex
A memória partilhada:
é uma zona de memória que pode ser acedida por um ou mais processo, ou threads, em paralelo
o acesso normalmente é controlado com recurso a um semáforo (mutex), ou outro mecanismo de sincronização / exclusão mutua
O mapeamento de ficheiros em memória:
usa-se para facilitar o acesso a ficheiros
o ficheiro comporta-se como uma zona de memória de acesso comum, como se fosse um array partilhado entre processos
CreateFile (abrir o ficheiro),
CreateFileMapping (mapear o ficheiro em memória),
MapViewOfFile (criar uma vista do ficheiro ou parte dele),
FlushViewOfFile (sincronizar memória e ficheiro),
UnmapViewOfFile (terminar vista do ficheiro),
CloseHandle (usado para terminar o mapping e fechar o ficheiro
A memória partilhada:
CreateFileMapping (mapear o ficheiro em memória, criar zona de memória),
OpenFileMapping (obter um ponteiro para zona de memória já criada),
MapViewOfFile (criar uma vista do ficheiro ou parte dele, cada processo cria a sua vista para poder trabalhar),
FlushViewOfFile (sincronizar memória e ficheiro),
UnmapViewOfFile (terminar vista do ficheiro),
CloseHandle (usado para terminar o mapping e fechar o ficheiro
outras funções:
GetSystemInfo
CopyMemory
#include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> int _tmain(int argc, TCHAR* argv[]) { HANDLE hMapeamentoFicheiro, hFicheiro; char* pBuffer, aux; TCHAR auxt; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif //criar o ficheiro hFicheiro = CreateFile( TEXT("letras.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if(hFicheiro == INVALID_HANDLE_VALUE) { _tprintf(TEXT("Erro a abrir o ficheiro - CreateFile (%d)\n"), GetLastError()); return 1; } //o mapeamento hMapeamentoFicheiro = CreateFileMapping(hFicheiro, NULL, PAGE_READWRITE, 0, 26, NULL); if(hMapeamentoFicheiro == NULL){ _tprintf(TEXT("Erro no file map (%d)\n"), GetLastError()); CloseHandle(hFicheiro); } //a vista pBuffer = (char*)MapViewOfFile( hMapeamentoFicheiro, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 26 ); //26 bytes, do tamanho da memória partilhada if(pBuffer == NULL) { _tprintf(TEXT("Erro ao criar view da memoria partilada (erro %d)\n"), GetLastError()); CloseHandle(hMapeamentoFicheiro); CloseHandle(hFicheiro); return 1; } _tprintf(TEXT("A modificar o ficheiro em memoria.\n")); for(unsigned int i = 0; i <13; i++) { aux = pBuffer[i]; pBuffer[i] = pBuffer[25 - i]; pBuffer[25 - i] = aux; } _tprintf(TEXT("Ficheiro por ordem inversa em memoria.\n")); for(unsigned int i=0; i< 26; i++) { _tprintf(TEXT("%c"), pBuffer[i]); } UnmapViewOfFile(pBuffer); CloseHandle(hMapeamentoFicheiro); CloseHandle(hFicheiro); return 0; }
um programa que recebe input de um utilizador
o programa escreve em memoria partilhada o que o utilizador escreve
o programa tem uma thread que esta sempre a tentar ler da memoria partilhada
e assim todos os outros programas leem essas mensagens
o acesso à memoria partilhada é controlado pelo mutex
o utilizador só escreve se o semáforo permitir
o controlo de entrada não pode ser feito com mutex, porque só deixa entrar um (é binário o controlo)
assim o mecanismo a usar é o semáforo (pode funcionar como uma pilha).
funções:
CreateSemaphore, OpenSemaphore, WaitForSingleObject, CloseHandle
#include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #define SEM_BOUNCER_NAME TEXT("SEMBOUNCER") //nome do semáforo #define MAXUSERS 3 //numero de processo que vão passar no semáforo typedef struct _ControlData{ //tipo de estrutura de dados de controlo HANDLE hSemBouncer; //semáforo } CData; int _tmain(int argc, TCHAR* argv[]) { HANDLE sem; // Handle do semáforo CData cdata; //estrutura de dados de controlo #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif cdata.hSemBouncer = CreateSemaphore( NULL, //atributo de segurança MAXUSERS, //começa o programa logo com o max users MAXUSERS, //limite de users SEM_BOUNCER_NAME //nome do semáforo ); if(cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nerro a criar semáforo")); return FALSE; }else { _tprintf(TEXT("Semáforo criado\n")); } cdata.hSemBouncer = OpenSemaphore( //abrir o semáforo SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, SEM_BOUNCER_NAME ); if(cdata.hSemBouncer == NULL) { _tprintf(TEXT("Problema na abertura do Semáforo (%d),\n"), GetLastError()); return FALSE; }else { _tprintf(TEXT("Semáforo aberto.\n")); } _tprintf(TEXT("Vou aguardar no semáforo para entrar\n")); WaitForSingleObject(cdata.hSemBouncer, INFINITE); _tprintf(TEXT("Entrei. Qualquer tecla para continuar\n")); _gettch(); ReleaseSemaphore(cdata.hSemBouncer, 1, NULL); _tprintf(TEXT("Semáforo libertado\n")); CloseHandle(cdata.hSemBouncer); return 0; }
#include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #define SEM_BOUNCER_NAME TEXT("SEMBOUNCER") //nome do semáforo #define MAXUSERS 3 //numero de processo que vão passar no semáforo #define SHM_NAME TEXT("fmMsgSpace") //nome da memória #define MUTEX_NAME TEXT("RWMUTEX") //nome do mutex #define MSGTEXT_SZ 100 //tamanho máximo das mensagens #define MSG_DELAY 500 //intervalo para leitura das mensagens pelos clientes typedef struct _MSG{ TCHAR szMessagem[MSGTEXT_SZ]; } Shared_MSG; typedef struct _ControlData{ //tipo de estrutura de dados de controlo HANDLE hSemBouncer; //semáforo //para o mutex HANDLE hMapFile, hRWMutex; Shared_MSG* shared; // ponteiro para memoria partilhada HANDLE newmsg; //ponteiro para o evento int continuar; // vairvel para terminar as threads } CData; //função que lê do teclado e envia para memoria partilhada void le_envia(CData * pcd) { Shared_MSG msg; //estrutura local while(pcd->continuar) { _tprintf(TEXT("Escreve mensagem (fim para sair)")); wscanf_s(TEXT("%s"), msg.szMessagem, (unsigned)_countof(msg.szMessagem)); //_tprintf(TEXT("%s\n"), msg.szMessagem); if(_tcscmp(msg.szMessagem, TEXT("fim"))==0) { break; } WaitForSingleObject(pcd->hRWMutex, INFINITE); CopyMemory(pcd->shared, &msg, sizeof(Shared_MSG)); ReleaseMutex(pcd->hRWMutex); //assinlar que há nova mensagem SetEvent(pcd->newmsg); //esperar que mensagem seja lida por outros processos Sleep(MSG_DELAY); //desativar evento ResetEvent(pcd->newmsg); } pcd->continuar = 0; _tprintf(TEXT("\nPrograma vai terminar")); //para desbloquear a outra thread e sair de imediato SetEvent(pcd->newmsg); } DWORD WINAPI recebe_msg(LPVOID p) { CData* pcd = (CData*)p; Shared_MSG msg; while(1) { WaitForSingleObject(pcd->newmsg, INFINITE); //aguardar evento if(!pcd->continuar) { break; } WaitForSingleObject(pcd->hRWMutex, INFINITE); //obter mutex CopyMemory(&msg, pcd->shared, sizeof(Shared_MSG)); ReleaseMutex(pcd->hRWMutex); _tprintf(TEXT("Recebi: %s\n"), msg.szMessagem ); Sleep(MSG_DELAY * 2); } //no cao de haver outras thread, evento não fica ativo para elas quando esta thread termina ResetEvent(pcd->newmsg); return 0; } int _tmain(int argc, TCHAR* argv[]) { HANDLE sem; // Handle do semáforo CData cdata; //estrutura de dados de controlo DWORD tid; //estrutura de dados de controlo #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif cdata.hSemBouncer = CreateSemaphore( NULL, //atributo de segurança MAXUSERS, //começa o programa logo com o max users MAXUSERS, //limite de users SEM_BOUNCER_NAME //nome do semaforo ); if(cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nerro a criar semaforo")); return FALSE; }else { _tprintf(TEXT("Semáforo criado\n")); } cdata.hSemBouncer = OpenSemaphore( //abrir o semaforo SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, SEM_BOUNCER_NAME ); if(cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nProblema na aberura do Semáforo (%d)"), GetLastError()); return FALSE; }else { _tprintf(TEXT("Semáforo aberto.\n")); } _tprintf(TEXT("\nVou agurdar no semáforo para entrar")); WaitForSingleObject(cdata.hSemBouncer, INFINITE); //criar a zona de memória cdata.hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Shared_MSG), SHM_NAME ); if (cdata.hMapFile == NULL) { _tprintf(TEXT("Problema em criar zona de memoria (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada zona de memoria.")); } //criar a zona de memória - a vista cdata.shared = (Shared_MSG*)MapViewOfFile( cdata.hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, //vista sobre a memoria inteira sizeof(Shared_MSG) ); if (cdata.shared == NULL) { _tprintf(TEXT("Problema em criar a vista (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada a vista.")); } //criar a zona de memória - o mutex (com um nome conhecido para todos os processos) cdata.hRWMutex = CreateMutex( NULL, FALSE, MUTEX_NAME ); if (cdata.hRWMutex == NULL) { _tprintf(TEXT("Problema em criar o mutex (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nmutex criado.")); } cdata.newmsg = CreateEvent(NULL, TRUE, FALSE, TEXT("Evento")); cdata.newmsg = OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, TEXT("Evento")); if(cdata.newmsg == NULL) { _tprintf(TEXT("Erro ao criar evento %s (%d).\n"), TEXT("Evento"), GetLastError()); return FALSE; }else { _tprintf(TEXT("\nEvento lançado com sucesso")); } _tprintf(TEXT("Lançar a thread para ouvir o que se passa\n")); cdata.continuar = 1; sem = CreateThread(NULL, 0, recebe_msg, &cdata, 0, &tid); le_envia(&cdata); _tprintf(TEXT("Este cliente vai fechar\n")); WaitForSingleObject(sem, INFINITE); _tprintf(TEXT("Thread ouvinte encerrada\n")); ReleaseSemaphore(cdata.hSemBouncer, 1, NULL); UnmapViewOfFile(cdata.shared); //memoria partilhada CloseHandle(cdata.hMapFile); CloseHandle(cdata.newmsg); CloseHandle(cdata.hSemBouncer); return 0; }
esta é uma versão melhorada do exercício anterior, já que permite ter um “control” que vai recebendo pedidos de “aviões” e que dá resposta (caso seja positiva) a cada um dos “aviões”
pelo “control” surge o seguinte:
#include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #define SEM_BOUNCER_NAME TEXT("SEMBOUNCER") //nome do semáforo #define MAXUSERS 3 //numero de processo que vão passar no semáforo #define SHM_NAME TEXT("fmMsgSpace") //nome da memória #define MUTEX_NAME TEXT("RWMUTEX") //nome do mutex #define MSGTEXT_SZ 100 //tamanho máximo das mensagens #define MSG_DELAY 500 //intervalo para leitura das mensagens pelos clientes typedef struct _MSG_AEROPORTO { TCHAR szMessagem[MSGTEXT_SZ]; int pidMessagemControl; //aviao int pidMessagemAviao; //areoporto int comando; //0, semResposta, 1 pedido de aeroporto, 2, ok aeroporto, -1 , erro aeroporto } Shared_MSG; typedef struct _ControlData { //tipo de estrutura de dados de controlo HANDLE hSemBouncer; //semáforo //para o mutex HANDLE hMapFile, hRWMutex; Shared_MSG* shared; // ponteiro para memoria partilhada HANDLE newmsg; //ponteiro para o evento int continuar; // vairvel para terminar as threads } CData; //função que lê do teclado e envia para memoria partilhada void le_envia(CData* pcd) { Shared_MSG msg; //estrutura local while (pcd->continuar) { msg.pidMessagemControl = GetCurrentProcessId(); _tprintf(TEXT("\n[control: %d] Escreve mensagem (fim para sair)"), msg.pidMessagemControl); wscanf_s(TEXT("%s"), msg.szMessagem, (unsigned)_countof(msg.szMessagem)); //_tprintf(TEXT("%s\n"), msg.szMessagem); if (_tcscmp(msg.szMessagem, TEXT("fim")) == 0) { break; } WaitForSingleObject(pcd->hRWMutex, INFINITE); CopyMemory(pcd->shared, &msg, sizeof(Shared_MSG)); //dest , source ReleaseMutex(pcd->hRWMutex); //assinlar que há nova mensagem SetEvent(pcd->newmsg); //esperar que mensagem seja lida por outros processos Sleep(MSG_DELAY); //desativar evento ResetEvent(pcd->newmsg); } pcd->continuar = 0; _tprintf(TEXT("\nPrograma vai terminar")); //para desbloquear a outra thread e sair de imediato SetEvent(pcd->newmsg); } DWORD WINAPI recebe_msg(LPVOID p) { CData* pcd = (CData*)p; Shared_MSG msg; TCHAR nome[MSGTEXT_SZ]; _tcscpy_s(nome, _countof(nome), _T("coimbra")); while (1) { WaitForSingleObject(pcd->newmsg, INFINITE); //aguardar evento if (!pcd->continuar) { break; } WaitForSingleObject(pcd->hRWMutex, INFINITE); //obter mutex CopyMemory(&msg, pcd->shared, sizeof(Shared_MSG)); //dest , source ReleaseMutex(pcd->hRWMutex); if(msg.comando == 1){ _tprintf(TEXT("\nRecebi: %s do %d\n"), msg.szMessagem, msg.pidMessagemAviao); if (wcscmp(msg.szMessagem, _T("coimbra")) == 0) { _tprintf(TEXT("\nSenhor aviao existe esse aeroporto.. volte sempre %d!"), msg.pidMessagemAviao); pcd->shared->pidMessagemAviao = msg.pidMessagemAviao; pcd->shared->comando = 2; //Sleep(MSG_DELAY); }else { pcd->shared->comando = -1; } }else { _tprintf(TEXT("\nAguardo por um pedido formal")); pcd->shared->comando = -1; } Sleep(MSG_DELAY * 2); pcd->shared->comando = -1; } //no cao de haver outras thread, evento não fica ativo para elas quando esta thread termina ResetEvent(pcd->newmsg); return 0; } BOOL comunicaAeroporto(BOOL valor) { HANDLE sem; // Handle do semáforo CData cdata; //estrutura de dados de controlo DWORD tid; //estrutura de dados de controlo #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif cdata.hSemBouncer = CreateSemaphore( NULL, //atributo de segurança MAXUSERS, //começa o programa logo com o max users MAXUSERS, //limite de users SEM_BOUNCER_NAME //nome do semaforo ); if (cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nerro a criar semaforo")); return FALSE; } else { _tprintf(TEXT("\nSemáforo criado")); } cdata.hSemBouncer = OpenSemaphore( //abrir o semaforo SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, SEM_BOUNCER_NAME ); if (cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nProblema na aberura do Semáforo (%d)"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nSemáforo aberto.")); } _tprintf(TEXT("\nVou agurdar no semáforo para entrar")); WaitForSingleObject(cdata.hSemBouncer, INFINITE); //criar a zona de memória cdata.hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Shared_MSG), SHM_NAME ); if (cdata.hMapFile == NULL) { _tprintf(TEXT("\nProblema em criar zona de memoria (%d),"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada zona de memoria.")); } //criar a zona de memória - a vista cdata.shared = (Shared_MSG*)MapViewOfFile( cdata.hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, //vista sobre a memoria inteira sizeof(Shared_MSG) ); if (cdata.shared == NULL) { _tprintf(TEXT("\nProblema em criar a vista (%d),"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada a vista.")); } //criar a zona de memória - o mutex (com um nome conhecido para todos os processos) cdata.hRWMutex = CreateMutex( NULL, FALSE, MUTEX_NAME ); if (cdata.hRWMutex == NULL) { _tprintf(TEXT("\nProblema em criar o mutex (%d),"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nmutex criado.")); } cdata.newmsg = CreateEvent(NULL, TRUE, FALSE, TEXT("Evento")); cdata.newmsg = OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, TEXT("Evento")); if (cdata.newmsg == NULL) { _tprintf(TEXT("\nErro ao criar evento %s (%d)."), TEXT("Evento"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nEvento lançado com sucesso")); } _tprintf(TEXT("\nLançar a thread para ouvir o que se passa")); cdata.continuar = 1; sem = CreateThread(NULL, 0, recebe_msg, &cdata, 0, &tid); le_envia(&cdata); _tprintf(TEXT("\nEste cliente vai fechar")); WaitForSingleObject(sem, INFINITE); _tprintf(TEXT("\nThread ouvinte encerrada")); ReleaseSemaphore(cdata.hSemBouncer, 1, NULL); UnmapViewOfFile(cdata.shared); //memoria partilhada CloseHandle(cdata.hMapFile); CloseHandle(cdata.newmsg); CloseHandle(cdata.hSemBouncer); valor = TRUE; return valor; } int _tmain(int argc, TCHAR* argv[]) { BOOL entra = FALSE; while (entra == FALSE) { entra = comunicaAeroporto(FALSE); } }
pelo “aviao” surge o seguinte:
#include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #define SEM_BOUNCER_NAME TEXT("SEMBOUNCER") //nome do semáforo #define MAXUSERS 3 //numero de processo que vão passar no semáforo #define SHM_NAME TEXT("fmMsgSpace") //nome da memória #define MUTEX_NAME TEXT("RWMUTEX") //nome do mutex #define MSGTEXT_SZ 100 //tamanho máximo das mensagens #define MSG_DELAY 500 //intervalo para leitura das mensagens pelos clientes typedef struct _MSG_AEROPORTO { TCHAR szMessagem[MSGTEXT_SZ]; int pidMessagemControl; //aviao int pidMessagemAviao; //areoporto int comando; //0, semResposta, 1 pedido de aeroporto, 2, ok aeroporto, -1 , erro aeroporto } Shared_MSG; typedef struct _ControlData { //tipo de estrutura de dados de controlo HANDLE hSemBouncer; //semáforo //para o mutex HANDLE hMapFile, hRWMutex; Shared_MSG* shared; // ponteiro para memoria partilhada HANDLE newmsg; //ponteiro para o evento int continuar; // vairvel para terminar as threads } CData; //função que lê do teclado e envia para memoria partilhada void le_envia(CData* pcd) { Shared_MSG msg; //estrutura local while (pcd->continuar) { msg.pidMessagemAviao = GetCurrentProcessId(); if (_tcscmp(msg.szMessagem, TEXT("fim")) == 0 || (pcd->shared->pidMessagemAviao == GetCurrentProcessId() && pcd->shared->comando == 2)) { _tprintf(TEXT("\ndone..")); break; } _tprintf(TEXT("\n[aviao: %d]Escreve mensagem (fim para sair)"), msg.pidMessagemAviao); wscanf_s(TEXT("%s"), msg.szMessagem, (unsigned)_countof(msg.szMessagem)); //_tprintf(TEXT("%s\n"), msg.szMessagem); msg.comando = 1; WaitForSingleObject(pcd->hRWMutex, INFINITE); CopyMemory(pcd->shared, &msg, sizeof(Shared_MSG)); //dest , source ReleaseMutex(pcd->hRWMutex); //assinlar que há nova mensagem SetEvent(pcd->newmsg); //esperar que mensagem seja lida por outros processos Sleep(MSG_DELAY); //desativar evento ResetEvent(pcd->newmsg); } pcd->continuar = 0; _tprintf(TEXT("\nPrograma vai terminar")); //para desbloquear a outra thread e sair de imediato SetEvent(pcd->newmsg); } DWORD WINAPI recebe_msg(LPVOID p) { CData* pcd = (CData*)p; Shared_MSG msg; while (1) { WaitForSingleObject(pcd->newmsg, INFINITE); //aguardar evento if (!pcd->continuar) { break; } WaitForSingleObject(pcd->hRWMutex, INFINITE); //obter mutex CopyMemory(&msg, pcd->shared, sizeof(Shared_MSG)); //dest , source ReleaseMutex(pcd->hRWMutex); if(msg.pidMessagemAviao == GetCurrentProcessId()){ _tprintf(TEXT("\nProblemas com o nome do aeroporto")); msg.comando = 1; }else { _tprintf(TEXT("\n..")); //_tprintf(TEXT("\nRecebi: %s do %d"), msg.szMessagem, msg.pidMessagemControl); } Sleep(MSG_DELAY * 2); } //no cao de haver outras thread, evento não fica ativo para elas quando esta thread termina ResetEvent(pcd->newmsg); return 0; } BOOL comunicaAeroporto(BOOL valor) { HANDLE sem; // Handle do semáforo CData cdata; //estrutura de dados de controlo DWORD tid; //estrutura de dados de controlo #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif cdata.hSemBouncer = CreateSemaphore( NULL, //atributo de segurança MAXUSERS, //começa o programa logo com o max users MAXUSERS, //limite de users SEM_BOUNCER_NAME //nome do semaforo ); if (cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nerro a criar semaforo")); return FALSE; } else { _tprintf(TEXT("Semáforo criado\n")); } cdata.hSemBouncer = OpenSemaphore( //abrir o semaforo SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, FALSE, SEM_BOUNCER_NAME ); if (cdata.hSemBouncer == NULL) { _tprintf(TEXT("\nProblema na aberura do Semáforo (%d)"), GetLastError()); return FALSE; } else { _tprintf(TEXT("Semáforo aberto.\n")); } _tprintf(TEXT("\nVou agurdar no semáforo para entrar")); WaitForSingleObject(cdata.hSemBouncer, INFINITE); //criar a zona de memória cdata.hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Shared_MSG), SHM_NAME ); if (cdata.hMapFile == NULL) { _tprintf(TEXT("Problema em criar zona de memoria (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada zona de memoria.")); } //criar a zona de memória - a vista cdata.shared = (Shared_MSG*)MapViewOfFile( cdata.hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, //vista sobre a memoria inteira sizeof(Shared_MSG) ); if (cdata.shared == NULL) { _tprintf(TEXT("Problema em criar a vista (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\ncriada a vista.")); } //criar a zona de memória - o mutex (com um nome conhecido para todos os processos) cdata.hRWMutex = CreateMutex( NULL, FALSE, MUTEX_NAME ); if (cdata.hRWMutex == NULL) { _tprintf(TEXT("Problema em criar o mutex (%d),\n"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nmutex criado.")); } cdata.newmsg = CreateEvent(NULL, TRUE, FALSE, TEXT("Evento")); cdata.newmsg = OpenEvent(SYNCHRONIZE | EVENT_MODIFY_STATE, TRUE, TEXT("Evento")); if (cdata.newmsg == NULL) { _tprintf(TEXT("Erro ao criar evento %s (%d).\n"), TEXT("Evento"), GetLastError()); return FALSE; } else { _tprintf(TEXT("\nEvento lançado com sucesso")); } _tprintf(TEXT("Lançar a thread para ouvir o que se passa\n")); cdata.continuar = 1; sem = CreateThread(NULL, 0, recebe_msg, &cdata, 0, &tid); le_envia(&cdata); _tprintf(TEXT("Este cliente vai fechar\n")); WaitForSingleObject(sem, INFINITE); _tprintf(TEXT("Thread ouvinte encerrada\n")); ReleaseSemaphore(cdata.hSemBouncer, 1, NULL); UnmapViewOfFile(cdata.shared); //memoria partilhada CloseHandle(cdata.hMapFile); CloseHandle(cdata.newmsg); CloseHandle(cdata.hSemBouncer); valor = TRUE; return valor; } int _tmain(int argc, TCHAR* argv[]) { BOOL entra = FALSE; while (entra == FALSE) { entra = comunicaAeroporto(FALSE); } _tprintf(TEXT("\ntou feliz... cara#######")); return 0; }
0 thoughts on “sessão 6 – Memória partilhada / Sincronização – II Memória partilhada e Semáforos”