Tutorial Allegro 5 #11 – Threads

Padrão

Olá pessoal! Continuando com a série de posts sobre Allegro 5, hoje vamos ver como utilizar threads em seus aplicativos. Pra quem não sabe, thread é a forma de um processo dividir a si mesmo em duas ou mais tarefas que podem ser executadas concorrentemente (virtualmente, “ao mesmo tempo”).

Existem diversas formas de implementar tais mecanismos a nível de linguagem de programação. Por exemplo, na API do Windows temos funções para isso, no Linux temos uma implementação conhecida como POSIX, dentre outras. Geralmente as bibliotecas para jogos multiplataforma (Allegro, SDL, etc.) implementam sua própria interface para a criação de threads, evitando que você tenha que modificar sua implementação para cada sistema operacional.

No exemplo, vamos fazer a atualização do título da janela através da uma thread. Vamos dar uma olhada no código e já comentamos sua implementação:

#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <stdio.h>
#include <stdbool.h>

const int LARGURA_TELA = 640;
const int ALTURA_TELA = 480;

ALLEGRO_BITMAP *imagem = NULL;
ALLEGRO_DISPLAY *janela = NULL;
ALLEGRO_EVENT_QUEUE *fila_eventos;
ALLEGRO_THREAD *thread = NULL;

bool inicializar();
bool carregar_arquivos();
void finalizar();
void *minha_thread(ALLEGRO_THREAD *thr, void *dados);
bool sair = false;

int main(void)
{
    if (!inicializar())
    {
        return -1;
    }

    if (!carregar_arquivos())
    {
        return -1;
    }

    // Cria a thread e a dispara
    thread = al_create_thread(minha_thread, NULL);
    al_start_thread(thread);

    al_draw_bitmap(imagem, 0, 0, 0 );
    al_flip_display();

    while (!sair)
    {
        while (!al_is_event_queue_empty(fila_eventos))
        {
			ALLEGRO_EVENT evento;
			al_wait_for_event(fila_eventos, &evento);

            if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
            {
                sair = true;
            }
        }
    }

    finalizar();
    return 0;
}

bool inicializar()
{
    if (!al_init())
    {
        fprintf(stderr, "Falha ao inicializar Allegro.\n");
        return false;
    }

    if (!al_init_image_addon())
    {
        fprintf(stderr, "Falha ao inicializar add-on para imagens.\n");
        return false;
    }

	janela = al_create_display(LARGURA_TELA, ALTURA_TELA);
    if (!janela)
    {
        return false;
    }
    al_set_window_title(janela, "Testando Threads");

	fila_eventos = al_create_event_queue();
	if (!fila_eventos)
	{
	    fprintf(stderr, "Falha ao criar fila de eventos.\n");
	    al_destroy_display(janela);
		return false;
	}

	al_register_event_source(fila_eventos, al_get_display_event_source(janela));

    return true;
}

bool carregar_arquivos()
{
    imagem = al_load_bitmap("imagem.jpg");
    if (!imagem)
    {
        fprintf(stderr, "Falha ao carregar imagem.\n");
        al_destroy_display(janela);
        al_destroy_event_queue(fila_eventos);
        return false;
    }

    return true;
}

void finalizar()
{
    al_destroy_thread(thread);
    al_destroy_event_queue(fila_eventos);
    al_destroy_bitmap(imagem);
    al_destroy_display(janela);
}

void *minha_thread(ALLEGRO_THREAD *thr, void *dados )
{
    while(!sair)
    {
        al_set_window_title(janela, "Thread disparada");
        al_rest(0.25);

        al_set_window_title(janela, "Thread disparada.");
        al_rest(0.25);

        al_set_window_title(janela, "Thread disparada. .");
        al_rest(0.25);

        al_set_window_title(janela, "Thread disparada. . .");
        al_rest(0.25);
    }

    return NULL;
}

Bom, o código possui poucos elementos novos para nós. O primeiro deles é a declaração da thread propriamente dita, que é declarada com o tipo ALLEGRO_THREAD. Outro item importante a ser considerado é a função que será executada pela thread. No nosso caso, é a função minha_thread(). Para adaptar-se a diversos formatos de função e retorno, as funções a serem utilizadas pela thread devem sempre ter o formato

void *funcao(ALLEGRO_THREAD thr, void *argumentos);

de forma que os ponteiros podem ser facilmente convertidos para qualquer outro tipo. Para a criação da thread, temos a chamada à função al_create_thread() que recebe como argumento a função que será executada e os parâmetros (no nosso caso, como não teremos parâmetros, passamos simplesmente NULL). Em seguida, disparamos a thread através da função al_start_thread(). A execução das threads pode ser interrompida por estruturas de semáforos para controlar problemas de exclusão mútua (mas isso fica pra um próximo post ;)). Ao final do aplicativo, desalocamos a thread através da função al_destroy_thread(), no caso desse exemplo, dentro da função finalizar().

A função vinculada à thread apenas atualiza o título da janela em intervalos de 1/4 de segundo. O nosso aplicativo deve ficar mais ou menos assim:

Para compilar:

  • Windows: -lallegro-5.0.5-mt -lallegro_image-5.0.5-mt
  • Linux: -lallegro -lallegro_image

É isso pessoal! Até a próxima!

Deixe uma resposta