Tag: SO2 – 2021 – Ficha 6 v.2.4 – Memoria Partilhada + Sincronizaao II.pdf

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;
}

Resultado:

#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;
}

Resultado:

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;
}
Tags : , , ,