Murilo :P

C++, Computação, Programação, Web e afins :)

Posts Tagged ‘thread

C++: Uma introdução a Threads com boost::thread

with 10 comments

boostPara quem ainda não conhece, Boost é um conjunto de bibliotecas C++ multiplataforma que trabalha bem com a STL e é muito bem aceita na comunidade. Já existem dez bibliotecas Boost incluídas no C++ TR1 e que estarão no C++0x além de muitas outras que estarão no C++0x e que atualmente não estão no TR1.

Para instalar o boost siga esse Getting Started.

Fazer threads com boost::thread é muito simples. Basta criar uma função ou um functor e passar pro construtor da classe boost::thread:

class functor
{
public: void operator()() {};
};

functor::operator()()
{
	/* content */
}

void function()
{
	/* content */
}

functor obj;
boost::thread tObj(obj); //passa uma cópia de obj
boost::thread tObjRef(boost::ref(obj)); //passa uma referência para obj
boost::thread tFunc(&funcao);

// aguarda a finalização das threads
tObj.join();
tObjRef.join();
tFunc.join();

//ou pode-se criar grupos de threads

boost::thread_group my_threads;
my_threads.create_thread(obj);
my_threads.create_thread(boost::ref(obj));
my_threads.create_thread(&function);

my_threads.join_all(); // aguarda o grupo de threads retornar

Para ilustrar como funciona, fiz dois programinhas simples:

cin.cpp

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>

//determina se o usuário já entrou com o número
bool flag = false;

struct in
{
	int n;

	in() : n(0) {};

	void operator()()
	{
		//try to read the number
		while (!(std::cin >> n)) {
			std::cin.clear();
			std::cin.ignore(10000, '\n');

			std::cout << "Enter a valid number" << std::endl;
		}
		
		flag = true;
	}

};

void my_alarm()
{
	while (!flag) {
		//shows the message
		std::cout << "Enter a number" << std::endl;
		
		boost::xtime time;
		boost::xtime_get(&time, boost::TIME_UTC); //current time

		time.sec += 5; //adds 5 secs to time
		//sleep 5 secs
		boost::thread::sleep(time);
	}

	//exiting function
	std::cout << "Alarm finished" << std::endl;
}

int main()
{
	in test;
	
	//create the two threads
	boost::thread tin(boost::ref(test));
	boost::thread tal(&my_alarm);

	// wait
	tin.join();
	tal.join();

	//show the user's number
	std::cout << "Ok " << test.n << std::endl;
	
	return 0;
}

Esse programa é composto por duas threads (fora o fluxo principal) uma que é responsável por fazer a leitura de um número e a outra que fica a cada 5 segundos mostrando uma mensagem “Enter a number” enquanto o usuário não digitar um número válido. Quando o usuário digita um número válido, a flag é setada e os loops das duas threads são finalizados. Finalmente quando as duas threads são finalizadas, o fluxo normal de main() é reestabelecido e é mostrado o número digitado pelo usuário.

Lembrando que para usar boost::thread é necessário “linkar” a biblioteca ao programa. No caso do Linux é necessário linkar também a biblietca pthread em Windows “linkar” a win32api. No meu caso preferi usar linkagem estática.

murilo@blacksheep:~/programacao/boost$ g++ cin.cpp libboost_thread-gcc43-mt-1_39.a -o cin -lpthread
murilo@blacksheep:~/programacao/boost$ ./cin
Enter a number
Enter a number
naoehumnumero
Enter a valid number
Enter a number
4
Alarm finished
Ok 4

O outro exempo que fiz é um programinha que faz a multiplicação de duas matrizes e “simultaneamente” (depende de processador e SO) mostra uma barra de progresso com o progresso da operação.

multiplica.cpp

#include <iostream>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>

const int MAX = 1000;

int A[MAX][MAX];
int B[MAX][MAX];
int C[MAX][MAX];

int porcentagem = 0;

void multiplica()
{
	int soma;	
	
	for (int i = 0; i < MAX; i++) {
		for (int j = 0; j < MAX; j++) {
			soma = 0;
			for (int k = 0; k < MAX; k++) {
				soma += A[i][k] * B[k][j];
			}
			
			C[i][j] = soma;			
		}
		if (i % 10 == 0) porcentagem++;
	}
}

void barra_de_progresso()
{
	int atual = 0;
	while (porcentagem != 100) {
		if (atual != porcentagem) {
			if (porcentagem % 10 == 0) {
				std::cout << "\b\b" << porcentagem << '%';
			}
			else std::cout << '=' << std::flush;
			
			atual++;
		}
	}
}

int main()
{
	boost::thread tMultiplica(&multiplica);
	boost::thread tProgresso(&barra_de_progresso);
	
	boost::xtime inicio, fim;
	boost::xtime_get(&inicio, boost::TIME_UTC);
	
	std::cout << "Iniciando a multiplicação de matrizes" << std::endl;
	
	tMultiplica.join();
	tProgresso.join();
	
	boost::xtime_get(&fim, boost::TIME_UTC);
	
	std::cout << "\n\nProcesso terminado em " << 
		(fim.sec - inicio.sec) << " segundos" << std::endl;
	
	return 0;	
}

Saída:

murilo@blacksheep:~/programacao/boost/thr$ g++ multiplica.cpp libboost_thread-gcc43-mt-1_39.a -lpthread -o multiplica
murilo@blacksheep:~/programacao/boost/thr$ ./multiplica
Iniciando a multiplicação de matrizes
=======10%=======20%=======30%=======40%=======50%=======60%=======70%=======80%=======90%=======100%

Processo terminado em 43 segundos

Claro que o que menos nos importa nesse momento é o valor das matrizes e a multiplicação em si, por isso nem me dei ao trabalho de inicializar as matrizes nem de fazer nada com a matriz resultante.

Acredito que para uma introdução está bom e deu pra mostrar como é fazer programas com boost::thread com esses simples exemplos. Mais exemplos você pode encontrar na pasta libs do boost.

Links:

Written by Murilo Adriano

6 de August de 2009 at 18:06

Posted in C/C++, Programação

Tagged with , , ,