quarta-feira, 13 de fevereiro de 2008

Linux - Programação C - Comunicação entre Processos

Comunicação entre processos

(IPC - Interprocess Communication)

Por Ricardo Lima Caratti

Implementando o Jogo da Velha utilizando Semáforo e Memória Compartilhada


É muito comum no mundo do desenvolvimento de aplicações, deparar-se com a necessidade de dois ou mais processos se comunicam entre si. Isso ocorre quando se deseja principalmente: Compartilhar informações pertinentes a dois ou mais processos, dividir sistemas complexos em módulos menores e aumentar a velocidade de processamento utilizando-se arquiteturas de hardware paralelas.

O Linux, bem como em outros sistemas operacionais, fornecem mecanismos que facilitam a comunicação entre processos. São eles: Pipes, Filas, Semáforos e Memória Compartilhada. Dado a extensão desse assunto, será visto aqui somente a utilização de Semáforos e de Memória compartilhada. Para ilustrar o uso de comunicação entre processos, será implementado o jogo da velha, onde duas cópias do mesmo processo compartilharão uma mesma região de memória. Mais informações sobre o jogo serão descritas a seguir.

Comunicando Processos por meio de Semáforo e Memória Compartilhada

A figura 1 mostra o diagrama de comunicação entre dois processos usando memória compartilhada e semáforo. Note que a função do semáforo é controlar o acesso a memória de tal forma que somente um processo de cada vez tenha acesso.

Figura 1 Os processos A e B compartilham informações contidas na memória. O semáforo controla acesso a memória.

Memória Compartilhada

Esse método consiste em fazer uso de uma área reservada de memória RAM onde os processos poderão trocar informações. Basicamente utiliza-se referências a uma região de memória em cada processo. Portanto, é a forma mais rápida de Comunicação entre Processos. A configuração para uso de memória compartilhada no Linux será vista mais adiante.

Semáforos

Na vida cotidiana, é possível observar a aplicação de semáforos nos cruzamentos de vias com alto fluxo de veículos. Nesse caso, o semáforo tem a função de controlar o fluxo de tal forma que todas a vias tenham condições de atender suas demandas. De forma similar em computação, semáforos são usados para gerenciar ações entres processos, reservando para cada um, o direito de ter acesso em um determinado momento a uma área de troca de informações.

Configurando o Linux para usar memória compartilhada para o programa Jogo da Velha.

Utilize um editor de texto e altere o arquivo lilo.conf existente no diretório /etc segundo mostrado a seguir em negrito:

image = /vmlinuz

append=”mem=XXm”

root=/dev/hda

label = linux

XX é a posição de memória que será reservada para compartilhamento, ou seja, se você tiver 32 MB de RAM XX deve ser igual a 31, indicado que o último MB de memória será reservado. Da mesma forma, se seu computador tiver 64 MB de RAM, utilize XX igual a 63.

Somente a linha em negrito deve ser incluída no arquivo. As demais dependerão da sua instalação, distribuição, versão do kernel e outras configurações. Portanto, não necessariamente serão iguais as apresentadas acima. Após a alteração do arquivo lilo.conf, execute o comando lilo a partir do prompt do shell. Em seguida o sistema deve ser reiniciado.

O programa Jogo da Velha

Para fazer demonstração do uso de Memória Compartilhada, foi desenvolvido o programa Jogo da Velha. Esse programa faz uso do segmento de memória compartilhada onde conterá as informações importantes do jogo. Você poderá jogar usando duas consoles ou terminais no KDE e executar o mesmo jogo em cada um. Idealmente, seria melhor executar o programa em máquinas distintas, ou seja, por meio de um telnet você poderia se conectar na máquina que contem o jogo e executar. O seu adversário poderia fazer o mesmo em um outro computador e também executar o mesmo jogo. Com isso, o programa automaticamente identificará que o jogo deu inicio e apresentará a seguinte tela:

Jogador1 x Jogador2

1 2 3

| |

1 | |

--------------

| |

2 | |

--------------

| |

3 | |

Entre com a Linha e a Coluna:

Para fazer uma jogada válida, você deve entrar com os valores de linha e coluna da seguinte forma:

11 se quiser marcar o quadro superior esquerdo, 22 se quiser marcar o quadro central. A figura abaixo mostra uma jogada onde o jogador marcou a linha 2 coluna 1.

1 2 3

| |

1 | |

--------------

X | |

2 X | |

--------------

| |

3 | |

Quando um jogador marcar uma linha ou uma coluna completa ou ainda preencher uma das diagonais, o jogo terminará dando a ele a vitória.

Fontes

O programa jogo da velha consiste em três arquivos fontes. semaforo.c, semaforo.h e JogoDaVelha.c. Semaforo.c é uma pequena biblioteca de funções para manipulação de semáforo. Os trechos considerados relevantes para compreensão do programa estão em negrito e serão comentados mais adiante. Em semaforo.h estão declaradas essas funções que serão usadas em JogoDaVelha.c.

Arquivo semaforo.h

int ObtemValor(int sid, int member);

int AbreSemaforo(int *sid, key_t key);

int CriaSemaforo(int *sid, key_t key, int members);

int LockSemaforo( int sid, int member );

int UnLockSemaforo( int sid, int member);

void RemoveSemaforo(int sid) ;

void RemoveSemaforo(int sid) ;

Arquivo semaforo.c

#include

union semun {

int val;

struct semid_ds *buf;

unsigned short int *array;

struct seminfo *__buf;

};

// Obtém o valor do semáforo

int ObtemValor(int sid, int member)

{

return ( semctl(sid,member, GETVAL,0) );

}

// Atribui um valor ao semáforo

int AtribuiValor(int sid, int member, int valor )

{

union semun semopts;

semopts.val = valor;

return (semctl(sid,member,SETVAL, semopts));

}

// Abre um semáforo; retorna -1 se não tiver sucesso.

int AbreSemaforo(int *sid, key_t key)

{

return ( (*sid = semget(key,0,0666)) == -1)? -1: *sid;

}

// Cria um semáforo; retorna -1 se não tiver sucesso.

int CriaSemaforo(int *sid, key_t key, int members)

{

int i;

union semun semopts;

if ((*sid=semget(key,members,IPC_CREAT|IPC_EXCL|0666))==-1)

return -1;

else {

semopts.val = 1;

for ( i= 0; i <>

semctl(*sid,i,SETVAL,semopts);

return *sid;

}

}

// Prende o semáforo ate a utilização de UnLockSemaforo, caso

// esteja em uso, espera ate ser liberado; retorna -1 se erro.

int LockSemaforo( int sid, int member )

{

struct sembuf sem_lock = {0,-1,0};

sem_lock.sem_num = member;

return ( (semop(sid,&sem_lock,1) ) == -1)? -1:(sid);

}

// Libera o semáforo permitido sua utilização; retorna -1 se erro

int UnLockSemaforo( int sid, int member)

{

struct sembuf sem_unlock = {member,1,0};

int semval;

sem_unlock.sem_num = member;

return ((semop(sid,&sem_unlock,1) ) == -1)? -1:(sid);

}

// Remove o semáforo

void RemoveSemaforo(int sid)

{

semctl(sid,0,IPC_RMID,0);

}

Arquivo JogoDaVelha.c

#include

#include

#include

#include "semáforo.h"

#define ENDERECO (63*0x100000)

struct jv {

int Jogador;

char Nome[2][20];

unsigned char Matr[3][3];

};

const char marca[] = { 'X','O'};

// Limpa a matriz do Jogo

void Limpa( unsigned char Matr[3][3] )

{

int i,j;

for ( i = 0; i <>

for (j = 0; j <>

Matr[i][j] = ' ';

}

// Verifica se existe alguma linha preenchida

int Linha(unsigned char Matr[3][3], int Jogador)

{

int i,j,k;

for ( i = 0; i <>

k = 0;

for ( j = 0; j <>

if (Matr[i][j]==marca[Jogador]) k++;

if ( k == 3 ) return 1; // Verdade

}

return 0; // Falso

}

// Verifica se existe alguma coluna preenchida

int Coluna( unsigned char Matr[3][3], int Jogador )

{

int i,j,k;

for ( i = 0; i <>

k = 0;

for ( j = 0; j <>

if (Matr[j][i]==marca[Jogador]) k++;

if ( k == 3 ) return 1; // Verdade

}

return 0; // Falso

}

// Verifica se Existe alguma diagonal preenchida

int Diagonal(unsigned char Matr[3][3],int Jogador)

{

return (Matr[0][0] == marca[Jogador] &&

Matr[1][1] == marca[Jogador] &&

Matr[2][2] == marca[Jogador]) ||

(Matr[0][2] == marca[Jogador] &&

Matr[1][1] == marca[Jogador] &&

Matr[2][0] == marca[Jogador]);

}

// Mostra a matriz do Jogo da Velha

void Mostra ( struct jv *jdv )

{

printf("\n%20s x %20s\n",jdv->Nome[0], jdv->Nome[1]);

printf("\n\n 1 2 3 ");

printf("\n1 %c | %c | %c ",jdv->Matr[0][0], jdv->Matr[0][1], jdv->Matr[0][2]);

printf("\n %c | %c | %c ",jdv->Matr[0][0], jdv->Matr[0][1], jdv->Matr[0][2]);

printf("\n -------------");

printf("\n2 %c | %c | %c ",jdv->Matr[1][0], jdv->Matr[1][1], jdv->Matr[1][2]);

printf("\n %c | %c | %c ",jdv->Matr[1][0], jdv->Matr[1][1], jdv->Matr[1][2]);

printf("\n -------------");

printf("\n3 %c | %c | %c ",jdv->Matr[2][0], jdv->Matr[2][1], jdv->Matr[2][2]);

printf("\n %c | %c | %c ",jdv->Matr[2][0], jdv->Matr[2][1], jdv->Matr[2][2]);

printf("\n");

}

// Programa Principal

int main()

{

int fd, id, Lin, Col, idx, Jogador;

char sCmd[4];

key_t chave_unica;

struct jv *JogoDaVelha;

// Cria ou abre um semáforo

chave_unica = ftok("/",'c');

if((id=AbreSemaforo(&id,chave_unica))==-1){

if((id=CriaSemaforo(&id,chave_unica,2)) ==-1){

AtribuiValor(id,0,1);

printf("\nNao foi possivel iniciar o jogo\n");

exit(2);

}

Jogador = 0;

printf("Você e o Jogador 1");

printf("\nAguardando outro jogador\n");

}

else {

Jogador = 1;

printf("\nVocê e o Jogador 2");

printf("\nJogo Iniciado\n");

}

// Abre device para manipular memória compartilhada

if ((fd = open("/dev/mem",O_RDWR)) <>

printf("\nNao foi possivel abrir mem. compartilhada!");

exit(1);

}

// Faz ponteiro da estrutura do jogo da velha apontar para memória comp.

JogoDaVelha = (struct jv *) mmap(0,sizeof(struct jv),PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, ENDERECO);

if ( Jogador == 0 )

JogoDaVelha->Jogador = 0;

printf("\nEntre com o seu nome: ");

fgets(JogoDaVelha->Nome[Jogador],20,stdin);

Limpa(JogoDaVelha->Matr);

while ( 1 )

{

LockSemaforo(id,1); // Segura a sua vez de jogar

if (ObtemValor(id,1) == -1) {

Mostra(JogoDaVelha);

printf("\nFim do Jogo.\nVoce Perdeu!\n");

return 0;

}

Mostra(JogoDaVelha);

// Jogada. Não permite uma jogada invalida

do {

printf("\nEntre com a Linha e a Coluna (exemplo: 11): ");

fgets(sCmd,3, stdin);

Lin = sCmd[0] - 48; // Converte valor da Linha para inteiro

Col = sCmd[1] - 48; // Converte valor da coluna para inteiro

if ( (Lin <> 3) || ( Col <>Col > 3 ) )

printf("\nEntrada Invalida!");

else {

Lin--;

Col--;

if ( JogoDaVelha->Matr[Lin][Col] != ' ' )

printf("\nJogada ha Efetuada. Tente Outra!");

else

break;

}

} while (1);

idx = JogoDaVelha->Jogador = Jogador; // Jogador da vez

JogoDaVelha->Matr[Lin][Col] = marca[idx]; // X ou O

// Verifica se houve vencedor

if(Linha(JogoDaVelha->Matr, JogoDaVelha->Jogador ) ||

Coluna(JogoDaVelha->Matr, JogoDaVelha->Jogador ) ||

Diagonal(JogoDaVelha->Matr, JogoDaVelha->Jogador) ) {

Mostra(JogoDaVelha);

printf("\nFim do Jogo\nVoce Venceu\n");

RemoveSemaforo(id);

return 0;

}

Mostra(JogoDaVelha);

UnLockSemaforo(id,1); // Libera para o outro jogar

sleep(2);

}

}

Comentários sobre os programas

As chamadas as funções do kernel bem como as funções padrões do C são ricamente comentadas nas documentações existentes no próprio Linux. Para saber sobre a função mmap por exemplo, basta executar o comando man mmap, da mesma forma, para saber mais sobre a função printf utilize o comando man printf. Portanto, essas funções não serão comentadas aqui.

Arquivo semaforo.c

union semun {

int val;

struct semid_ds *buf;

unsigned short int *array;

struct seminfo *__buf;

};

Essa estrutura é a utilizada pelas funções de chamadas ao kernel para manipular semáforos.

semctl

Essa função, dependendo dos seus argumentos, poderá ter várias utilidades. Aqui ela é usada praticamente para Ler um valor do semáforo ou para gravar um valor. Veja mais executando o comando man semctl.

semget

Essa função é usada para Criar ou abrir um semáforo dependendo dos seus argumentos. Veja mais executando o comando man semget.

semop

Essa função é utilizada para fazer operações com o semáforo. É utilizada para segurar ou liberar um recurso. Veja mais com man semop.

Arquivo JogoDaVelha.c

#define ENDERECO (63*0x100000)

define a posição de memória que será mapeada pela função mmap.

struct jv {

int Jogador;

char Nome[2][20];

unsigned char Matr[3][3];

};

Essa e a estrutura necessária para conter as informações do jogo. Jogador conterá 0 ou 1 dependendo de quem for a vez de jogar, Nome[2][20] conterá os nomes dos jogadores e Matr[3][3] conterá a matriz do jogo da velha.

const char marca[] = { 'X','O'};

Essa constante contem a marca de cada jogador, ou seja se for o jogador 0, será X, se for o jogador 1 será O.

chave_unica = ftok("/",'c');

A variável chave_unica conterá um identificador único obtido pela função ftok. Isso é necessário para não haver conflito com outros programas que usam memória compartilhada. Veja mais sobre ftok usando man ftok.

if((id=AbreSemaforo(&id,chave_unica))==-1){

if((id=CriaSemaforo(&id,chave_unica,2)) ==-1){

AtribuiValor(id,0,1);

printf("\nNao foi possivel iniciar o jogo\n");

exit(2);

}

Jogador = 0;

printf("Voce e o Jogador 1");

printf("\nAguardando outro jogador\n");

}

else

{

Jogador = 1;

printf("\nVoce e o Jogador 2");

printf("\nJogo Iniciado\n");

}

No trecho acima, a função AbreSemaforo tenta abrir o semáforo. Caso não consiga, ou seja retorne –1, então é assumido que o semáforo ainda não foi criado. Nesse caso a função CriaSemaforo entra em ação e cria um semáforo. Caso a função CriaSemaforo falhe, ou seja, retorne -1, o programa sair imediatamente informado que houve uma falha. Nesse caso o jogo não prossegue.

if ((fd = open("/dev/mem",O_RDWR)) <>

printf("\nNao foi possivel abrir mem. compartilhada!");

exit(1);

}

Nesse trecho, é usada a chamada ao kernel open para abrir um dispositivo de manipulação memória.

JogoDaVelha = (struct jv *) mmap(0,sizeof(struct jv), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, ENDERECO);

O trecho anterior, usa a função mmap para manipular o segmento de memória compartilhada reservada pelo sistema. Note que ela usa a variável fp que recebeu um descritor por meio da função open. Veja mais sobre mmap usando man mmap.

LockSemaforo(id,1); // Segura a sua vez de jogar

O código acima, chama a função LockSemaforo implementada em semáforo.c e que na realidade é uma abstração para a função semop. Sua função é prender o recurso de tal forma que o outro jogador não possa jogar.

if(Linha(JogoDaVelha->Matr, JogoDaVelha->Jogador ) ||

Coluna(JogoDaVelha->Matr, JogoDaVelha->Jogador ) ||

Diagonal(JogoDaVelha->Matr, JogoDaVelha->Jogador) ) {

Mostra(JogoDaVelha);

printf("\nFim do Jogo\nVoce Venceu\n");

RemoveSemaforo(id);

return 0;

}

O trecho acima chamas as funções auxiliares Linha, Coluna e Diagonal, implementadas no arquivo principal, JogoDaVelha.c, para testar se o jogador conseguio preencher um linha, uma coluna ou uma diagonal. Caso afirmativo, o jogo e encerrado dando a vitória para o jogador da vez.

UnLockSemaforo(id,1); // Libera para o outro jogar

Ao contrário de LockSemaforo, a função UnLockSemaforo dá a oportunidade ao outro jogador. Ela também é uma abstração para a função semop.

Compilação do programa

Utilize seqüência de comandos a seguir para compilar e gerar o programa executável:

gcc –c semaforo.c

gcc –o jogodavelha jogodavelha.c semaforo.o

Conclusão

O Jogo da Velha foi só um exemplo de como usar memória compartilhada e semáforos no Linux. Essa técnica poderá trazer grandes benefícios em desenvolvimento de aplicações profissionais. Principalmente quando há a necessidade de criar módulos ou programas independentes que tenham a necessidade de interação. Dentre as formas de comunicação entre processo mencionadas no início deste artigo, Memória Compartilhada se destaca pela sua facilidade em usar e pela sua notável performance.


Referências Bibliográficas

· GOLDT, SEVEN.The Linux Programmer´s Guide,Version 0.4,1997(Existente no formato PDF e distribuído no Cd da RevistaDoLinux Nº 4).

· WALL, WATSON, AND WHITIS. Linux Programming. SAMS, 1999;

· TANENBAUM, ANDREW S. Operating Systems Design and Implementation. Prentice-Hall, 1987;

· STEVENS, W. RICHARD. Unix Network Programming. Volume 2, 2ª ed. , Prentice Hall, 1999;

· BACH, MAURICE J. The Design of the Unix Operating System. Prentice Hall, 1986;


domingo, 10 de fevereiro de 2008

Administração de Dados

ADMINISTRAÇÃO DE DADOS

PADRONIZAÇÃO PARA NOMES E IDENTIFICADORES

Por Ricardo Lima Caratti

Uma breve introdução sobre Administração de Dados


A Administração de Dados é um tema pouco abordado em livros e em periódicos. Em muitos dos casos ela é confundida com a Administração de Banco de Dados e, quando existente em uma corporação, é exercida de forma tácita e não institucional. Muitos acreditam que o papel do Administrador de Dados (AD) se limita a criar e impor padrões que deverão ser seguidos por toda a equipe de desenvolvimento. Embora a padronização seja umas das ferramentas de trabalho para o uso estratégico da informação, veremos que a Administração de Dados é algo muito mais abrangente e de extrema importância para uma corporação.


Objetivos Principais da Administração de Dados


A Administração de Dados tem como principal objetivo gerenciar as estruturas de dados da corporação, promovendo sua conceituação, segurança, integridade e compartilhamento. Poderíamos detalhar isso da seguinte forma:


Garantir o uso estratégico das informações, identificando suas necessidades e oportunidades;

Melhorar a qualidade, a precisão e integridade dos dados;

Melhorar o compartilhamento dos dados na corporação;

Manter os modelos de informações atualizados;

Retirar dos Analistas e Desenvolvedores a responsabilidade da organização e estruturação dos dados;

Fornecer suporte a equipe de desenvolvimento;

Refinar e reaproveitar as informações da corporação.


Atividades da Administração de Dados

As principais atividades de um AD são:


Participar dos levantamentos de dados, eventos/funções e regras de negócio junto às áreas funcionais da corporação;

Elaborar e acompanhar a confecção dos modelos Conceituais de Dados.

Participar da integração do planejamento de sistemas com os modelos de Dados.

Responsabilizar-se pela qualidade e compatibilidade dos modelos de dados com os modelos de implementação;

Planejar e coordenar a evolução do Banco de Dados da corporação;

Definir, manter e auditar o Dicionário de Dados;

Desenvolver os mecanismos necessários para a adaptação dos sistemas legados.


Instrumentos de apóio a Administração de Dados


Dicionário de Termos;

Dicionário de Dados;

Dicionário de Acrônimos e Abreviações;

Documentação dos Projetos;


Perfil do Administrador de Dados


Análise de Sistema, sobretudo no que se refere a levantamentos de requisitos;

Boa capacidade de abstração;

Habilidade de mensurar a qualidade dos dados, segurança e facilidade de acesso;

Bom relacionamento com os envolvidos em cada projeto da corporação;

Boa noção sobre a metodologia aplicada para o desenvolvimento de sistema;

Conhecimento em Modelagem de Dados;

Conhecimento em ferramentas de apóio a modelagem de dados;

Conhecimento desejável:

Experiência em desenvolvimento de Sistemas;

Sistemas de Gerenciamento de Banco de Dados;

Linguagem SQL ou correlata;

UML;


PADRONIZAÇÃO DE NOMES DE ENTIDADES E ATRIBUTOS


Os “Nomes” são utilizados para identificar fatos sobre objetos, conceitos e eventos. Eles são de extrema relevância para a disseminação do conhecimento existente sobre os dados de uma corporação. Um bom padrão deve ser construído de tal forma a ser fácil de ser seguido por todos os envolvidos, desde o mais alto escalão da corporação até os gerentes de projeto, analistas, programadores e, em alguns casos, os usuários finais. Assim, a padronização de nomes deve estar presente tanto no modelo lógico quanto no modelo físico de dados. Nesse contexto, definimos “Nome” como uma palavra ou combinação de palavras no qual um elemento de dado pode ser conhecido. Assim, cada nome deve ser identificado dentro de um contexto, cada elemento de dado deve ter pelo menos uma palavra que o identifique.


Para abordar aspectos referentes a padronização de “Nomes” alguns conceitos podem ajudar na compreensão.


“Metadados"


Em sistemas de informações, entende-se por metadados informações sobre os dados. Ele é, sem sombra de dúvida, a ferramenta mais utilizada no gerenciamento de dados. Por isso, a padronização é um elemento necessário para assegurar que usuários e desenvolvedores entendam as informações que serão acessadas.


“Metadados” pode ser classificado em “metadado de negócio” e “metadados técnico”. “Metadados” de negócio são usados por analistas e usuários e provêem descrição sobre os elementos de informação. Eles estão mais associados aos modelos lógicos de dados. Os meta dados técnico são utilizados por administradores de sistema, desenvolvedores e ferramentas de software. Eles provêem descrições sobre os dados e as operações relacionadas a eles.


A utilização de um repositório de “Metadados” possibilita um meio para gerenciar informações sobre dados, aumentando assim, a produtividade no desenvolvimento de sistema de informação além de orientar usuários finais na localização e compreensão dos dados;


Modelo lógico de dados


O modelo lógico de dados serve para mostrar os dados que as aplicações devem armazenar satisfazendo os requisitos de negócios. Ele também mostra como esses dados estão relacionados. Em geral ele pode ser criado sem nenhum ambiente computacional em mente, ou seja, sem nenhuma consideração a questão de performance, armazenamento de dados, ambiente de desenvolvimento e hardware.


Modelo físico de dados


O modelo físico de dados serve para mostrar como os elementos de dados serão armazenados no banco de dados. As entidades e atributos do modelo lógico são mapeados para tabelas e colunas do modelo físico. O modelo físico muitas vezes pode introduzir objetos que não contribuem diretamente com os requisitos de negócios. Esses objetos podem ser criados por motivos de performance, redução de necessidade de armazenamento ou até mesmo para simplificar o desenvolvimento da aplicação.


PRINCÍPIOS DE CONVENÇÃO DE “NOMES” E IDENTIFICADORES


Nomes ou identificador podem ser definidos como palavras ou combinação de palavras dos quais os elementos de dados são conhecidos. Nomes podem ser combinados de tal forma a seguir uma regra de formação. Em muitos dos casos essas regras são construídas e utilizadas de acordos com as necessidades de uma corporação. No entanto a idéia de uma regra de formação permanece constante.


As regras ou conjunto de regras para formação de nomes devem ser seguidas e utilizadas em qualquer nível de desenvolvimento de uma corporação, ou seja, não deve ser restrita ao desenvolvimento de aplicação computacionais. Dado a importância do tema, a ISO desenvolveu um padrão para formação de nomes. Ele é baseado nas regras de composição de nome descritas acima. Trata-se da ISO/IEC -11179, que consiste das seguintes partes: 1-Cuida da especificação e padronização de elementos de dados; 2 – Classificação de elementos de dados; 3 - Atributos Básicos e Registro de “metamodelos”; 4 – Regras e guias para definição de formulação de dados; 5 – Princípios de formação de Nomes e Identificadores; 6 – Registro de elementos de dados. Falaremos aqui sobre a parte 5 do ISO/IEC – 11179.


O Padrão ISO/IEC 11179-5


Principais Características


Possibilita acesso e busca por conteúdo semântico em coleções de “metadados”;

Promove o uso de padrões para maior interoperabilidade;

Descreve a padronização e registro de elementos dados para fazer com que eles sejam compreensíveis e compartilhados;

Fornece um guia para regra de formação de nomes e definição de elementos de dados;

Nome de tags em XML seguem a convenção W3C que é baseada na ISO11179;

Dentre várias vantagens em utilizar o padrão ISSO/IEC 11179 destacam-se: É um padrão internacional estabelecido, é amplamente utilizado pelas agências governamentais; é facilmente integrável em esquemas de banco de dados e pode ser facilmente implementado em um LDAP (serviço de diretório);


As três regras principais para a composição de um nome são:


Regras semânticas, que são baseadas combinação de nomes, ou seja, utiliza qualificadores para enquadrar elementos de dados em um contexto;

Regras sintáticas, que descrevem como serão arranjados os elementos dentro de um nome;

Regras Léxicas, que diz respeito aos aspectos de um idioma ou linguagem, ou seja, termos preferidos e não preferidos, Sinônimos, Abreviações, Tamanhos, Conjunto de caracteres permitidos, utilização de maiúsculos e minúsculos;


Sugestões para formação de nomes


Como dito anteriormente, modelos lógicos de dados são gerados, além de outras coisas, para identificação de cada entidade e de seus atributos. Uma entidade ou objeto pode ser uma pessoa, uma coisa ou ainda um evento. O nome para definir cada objeto deve ser único dentro da corporação. A mesma idéia deve ser entendida para nomes de atributos, ou seja, ele deve ser único dentro de uma entidade. Assim, nomes para entidades e atributos devem ser o mais próximos do mundo real. Isso facilitará a leitura e compreensão dos modelos de dados.


Regra geral


Cada nome deve consistir de uma ou mais palavras que defina precisamente o propósito ou uso do elemento de dado;

O nome deve refletir o significado do negócio muito mais que o meio onde ele será armazenado ou processado;

Nome para elemento de dado deve estar no singular (Exemplo: Para entidade Funcionário, utilize “Funcionario” e não “Funcionarios”);

A palavra principal que compõe um elemento de dado não deve ser abreviada;

Utilize abreviações somente se for de aceitação e conhecimento geral da corporação;

Use todos os modificadores necessários para completa identificação do elemento de dados (Exemplo: Para “Nome do Empregado”, utilize NomeEmpregado no lugar de Nome);

Coloque os modificadores em uma seqüência lógica de tal forma que dê um significado preciso em Português (Exemplo: Para “Data de Nascimento”, utilize DataNascimento e não NascimentoData);

Se uma das palavras que compõe um Nome for um verbo, utilize-a no presente;

Usar a forma no substantivo sempre que possível (Exemplo: FUNCIONARIO, ORGAO, etc);

Se oportuno, para tornar mais claro, usar substantivo + adjetivo da seguinte forma: substantivo_adjetivo ou SubstantivoAdjetivo. Exemplo: HISTORICO_FUNCIONAL ou HistoricoFuncional. Lembrando que algumas implementações de SGBD não fazem distinção de maiúsculas e minúsculas. Assim, HistoricoFuncional poderia se tornar HISTORICOFUNCIONAL, podendo dificultar a compreensão.

Acrônimos ou siglas são bem vindos quanto estes são universalmente aceito. Exemplo: RG para registro geral, CEP para código de endereçamento postal, etc. Siglas podem ser oportunas para compor o nome de um esquema de banco de dados. Exemplo: Sistema de Recursos Humanos poderia ficar SRH. Entende-se por esquema de banco de dados como uma descrição de um banco de dados e não o banco de dados em si.

Evite tamanho de nomes muito longos. Sabe-se que algumas plataformas de banco de dados não suportam tamanhos maiores que 18 caracteres;

Utilize os Caracteres de A-Z e a-z para a identificação. Evite caracteres acentuados, espaços e outros que possam causar problemas quando incorporados a um SGBD. Leve sempre em consideração a portabilidade;



Exemplos de “Nomes” utilizados para Entidades e Atributos


A tabela abaixo mostra um pequeno exemplo de adoção de nomes para Entidades e Atributos.


Entidade


Atributo


Descrição








Funcionario


Matricula


Identificação do Funcionário




NomeFuncionario


Nome do Funcionário




DataNascimento


Data de Nascimento do Funcionário




NomePai


Nome do Pai do Funcionário




NomeMae


Nome da Mãe do Funcionário




CodigoEscolaridade


Código da Escolaridade do Funcionário




CodigoGrupoSanguineo


Código do Grupo Sangüíneo do Funcionário




.....



Escolaridade


Código Escolaridade


Código da Escolaridade




Descrição


Descrição da Escolaridade




....



GrupoSanguineo


CodigoGrupoSanguineo


Código do Grupo Sangüíneo




Descrição


Descrição do Grupo Sangüíneo




....



Tabela 1 – Exemplo de Nomes de Entidades e Atributos




Conclusão


A precisão e a integridade dos dados bem como a garantia do uso estratégico das informações de uma corporação são, dentre outros, os principais desafios da Administração de Dados. A utilização de um padrão de regra de formação de “Nomes” pode servir de ferramenta de trabalho para o Administrador de Dados. Nesse sentido, o padrão ISO/IEC 11179 poderá ajudar na utilização de um bom padrão.

Referências


Padrão ISO/IEC 11179-5, ISSO/IEC JTC1 SC36 N0555;

UC Davis Information Naming Standards, Data Administration Plan & Budget Office, Universidade da California, Versão 1.2, 22/07/1999;

University of Pennsylvania, http://www.upenn.edu/computing/da/;

Southwest Oregon Province, http://ims.reo.gov/website/swop/html/swop_slide_show/swop_sdm_whitepaper/sdm.htm#IV.

The University of Arizona, http://w3fp.arizona.edu/dataadmn/



sábado, 9 de fevereiro de 2008

Monitoração de Sistemas de Banco de Dados

Monitoração de Sistemas de Banco de Dados

Por Ricardo Lima Caratti

A disponibilidade do banco é um fator crítico para aplicações que manipulam bases de dados. Sistemas fora do ar por alguns minutos podem causar o descontentamento de milhares de usuários. Além da infra-estrutura de hardware e software projetada para garantir tal disponibilidade, é necessária a observação atenta e contínua do estado do SGBD. Neste artigo conheceremos algumas ferramentas de monitoração de banco de dados.

Métodos de Monitoração de Banco de Dados

Atividades de monitoramento podem ser efetuadas de duas formas: contínua ou sob demanda. Quando contínuas (ou pró-ativas), as atividades buscam prever e evitar o surgimento de problemas. Já as atividades por demanda (ou reativa) agem após a identificação de um problema já ocorrido. Um exemplo de utilização do monitoramento por demanda está relacionado a questões de desempenho. Imaginemos que um novo módulo de um aplicativo entrou em produção e em um dado momento o tempo de resposta do sistema aumentou de forma não esperada. Nesse caso, poderia ser detectado que uma determinada consulta foi construída de forma não otimizada.

O monitoramento pró-ativo consiste em fazer previsões baseadas em informações estatísticas extraídas do próprio SGBD e do sistema operacional. De posse desses dados, ele deve decidir se há necessidade de executar uma ação que previna a parada parcial ou total do sistema. Por exemplo, um monitor pró-ativo pode detectar que uma tabela irá alcançar sua alocação máxima e automaticamente estender essa alocação para que o sistema continue funcionado.

Embora o método reativo tenha seu espaço nas atividades de monitoração, o método pró-ativo é, sem dúvida, a forma mais eficaz de monitoramento no que tange a disponibilidade do SGBD. No entanto, é preciso ter cuidado com a utilização indiscriminada desses monitores, pois a verificação contínua do sistema pode causar impacto negativo no desempenho do SGBD. Nesse contexto, a monitoração pode ser classificada em intrusiva e não intrusiva, dependendo da interferência que ela causa no sistema.

Monitoração Intrusiva

Em muitos casos, é necessário obter informações internas do SGBD, como a quantidade de blocos ocupados por uma tabela ou como esses blocos estão distribuídos. Essas informações são importantes e necessitam de um acompanhamento periódico. No entanto, sua obtenção consome recursos do SGDB sendo necessário o cuidado para não sobrecarregá-lo. Fica claro que uma definição sensata da periodicidade em que as checagens serão feitas é fundamental. Outros exemplos comuns de monitoração intrusiva são: fazer o acompanhamento das atividades de um usuário ou grupo de usuários em particular para fins de depuração ou auditoria; fazer o acompanhamento em intervalos de tempo da taxa de crescimento de uma tabela e a avaliação do estado de fragmentação dos grupos de arquivos do SGBD.

Monitoração não Intrusiva

Como vimos, é muito importante que o monitoramento não afete negativamente o desempenho do SGBD. Para isto, as ferramentas de monitoração devem aproveitar ao máximo os recursos nativos de cada SGDB.
Diversos “fabricantes” de bancos de dados disponibilizam interfaces de programação para o desenvolvimento de mecanismos de monitoração para seu produto. Através dessas interfaces é possível obter informações diretamente da estrutura de memória do SGBD com impacto mínimo de performance. A ORACLE, por exemplo, oferece a visão V$SESSION para verificar as sessões de usuário conectados no SGBD. De forma similar, o MS SQL Server oferece a storade procedure sp_who.

O que Esperar de um Sistema de Monitoramento?

Considerando o que foi apresentado até o momento, já é possível fazer uma projeção de um sistema de monitoramento. Porém, surgem algumas questões:
Quais dados serão coletados?
Como fazer a coleta?
Como será criado um repositório centralizado para guardar informações?
Como o SGBD será acessado?
Como essas informações serão apresentadas?

Na maioria dos livros e manuais de SGBD, monitoração é um tema intimamente ligado a refinamento, ou seja, monitorar para otimizar performance. No entanto, sabe-se que o refinamento tende a ser muito mais eficiente na fase de Projeto e Desenvolvimento de um sistema do que durante a produção. Ou seja, quando um sistema entra em produção, é desejável que ele já esteja otimizado, restando para a monitoração o papel de identificar fatores que venham a comprometer sua disponibilidade.
Pensando assim, um bom monitor pró-ativo tem como componente fundamental o repositório de dados. O principal objetivo desse repositório é indicar tendências comportamentais do SGBD, como taxa de crescimento de usuários simultâneos, taxa de crescimento de dados, consumo de recursos do sistema e horários de pico. Dessa forma, uma análise temporal das informações do repositório poderá apoiar as tomadas de decisão do DBA.

Considerando que um DBA não está 24h no ambiente de trabalho, um bom monitor deverá tomar ações para impedir a parada do sistema sem a intervenção imediata do DBA. Por exemplo, ao coletar a informação de espaço disponível no disco, caso o valor atual não esteja dentro do limite considerado crítico, o monitor poderia efetuar determinadas ações como enviar uma mensagem de alerta para o DBA ou remover arquivos temporários para liberar mais espaço. A seguir são apresentadas algumas informações importantes a serem coletadas pelo monitor:

SGBD: Sessão de usuário, utilização de memória, utilização de espaço de armazenamento, performance geral do sistema, atividades de backup e recovery, contenção de bloqueios (locks) e transações por minuto.
NO-BREAK: Os NO-BREAKs modernos possuem uma interface de comunicação com o computador, sendo possível monitorar as condições das baterias, temperatura interna, oscilação e falta de energia elétrica.
SISTEMA OPERACIONAL: CPU, memória, espaço em disco, processos de usuário e rede.

O monitoramento do sistema operacional é importante, pois em muitos casos um problema pode estar mais relacionado aos recursos gerenciados por ele do que pelo SGDB. Considere, por exemplo, um processo “pesado” sendo executado pelo usuário em horário de pico (um antivírus, por exemplo).
A ampla gama de sensores de monitoração disponíveis atualmente permite que fatores externos ao SGBD sejam também monitorados, como:

Temperatura do ambiente: Caso exista alguma falha no sistema de refrigeração, a temperatura poderá subir de forma que possa comprometer o funcionamento dos computadores.
Umidade do ambiente: Ambientes muito úmidos podem prejudicar o funcionamento do computador.
Temperatura interna da CPU: Por mau funcionamento ou condições extremas, a temperatura da CPU poderá subir para valores críticos.
Temperatura dos Arrays de Discos: O uso intenso de I/O poderá superaquecer os discos.
Falha em algum disco do Array: Os atuais sistemas de array de discos possibilitam realizar manutenções sem necessidade de parar o sistema. Assim, monitorar as condições dos discos é importante e desejável.
Fontes de alimentação: Computadores projetados para alta disponibilidade vêm com duas ou mais fontes de alimentação permitindo que uma entre em funcionamento caso a outra falhe.

Onde Encontrar Ferramentas de Monitoração

Alguns SGBDs já trazem ferramentas de monitoração em seu pacote. Existem também fabricantes de softwares especializados nessa tarefa, como por exemplo a BMC Software (http://www.patrol.com/), Quest Software (http://www.quest.com/) e Veritas (http://www.veritas.com). Essas ferramentas estão disponíveis para os principais SGBD comerciais e podem ser consultadas nos sites apresentados. Algumas características dessas ferramentas são mostradas a seguir.
Ferramenta da Quest Software
A Quest Software possui um conjunto de ferramentas que possibilitam ao DBA monitorar e diagnosticar, em tempo real, várias condições de estado do SGBD. As principais características dessas ferramentas são:

Representação visual dos fluxos das atividades do SGBD;
Suporte a monitoração de múltiplos serviços de banco de dados ao mesmo tempo;
Suporte a monitoração de sistema operacional;
Suporte a identificação de gargalos;
Visualização imediata de áreas e situações problemáticas;
Alerta de contenção de recursos de SGBD;
Assistente que ajuda em reparos e refinamentos on-line;
Integração com outras ferramentas para suporte a monitoração pró-ativa em SGBD 24/7. Isso inclui envio de mensagens ao DBA via celular, page ou e-mail;
Apresentação detalhada de consultas em SQL ineficientes, utilização de memória, utilização de I/O, transações e bloqueios (locks).

Ferramenta da Patrol (BMC Software)

A Patrol também possui um conjunto de ferramentas que, na mesma linha da Quest Software, possibilitam a monitoração do SGBD e sistema operacional. Suas principais características são:

Condição de performance em tempo real dos servidores de banco de dados;
Visualização imediata de áreas e situações problemáticas;
Isolamento da causa do problema;
Análise de performance;
Dados estatísticos acumulados em repositório;
Alerta de contenção de recursos de SGBD;
Alerta de falta de espaço;
Condição e utilização de memória.


Conclusão

Vimos neste artigo uma introdução a algumas ferramentas para monitoração de banco de dados. Infelizmente não tive oportunidade de avaliar a ferramenta da Precise (Indepth). Porém, pelo que pude ver no site (http:/veritas.com/), ela possui funcionalidades equivalentes às apresentadas pela Quest e Patrol. Gostaria de complementar dizendo que as observações sobre as ferramentas apresentadas aqui são superficiais e servem apenas para dar uma idéia ao leitor das facilidades presentes nelas.

Referências

ARONOFF, Eyal, LONEY, Kevin, SANAWALLA, Noorali, ORACLE 8 Advanced Tuning & Administration, Berkeley, California, Oracle Press, 1998
CYRAN, Michele, Desinginig and Tuning for Performance, Release 2 (8.1.6), Oracle Corporation, 1999.
DATE, C. J., Introdução a Sistema de Banco de Dados, 7ª ed. [Tradução: Vandenberg D. de Souza], Rio de Janeiro, 2000.
MOLINA, Hector Garcia, ULMAN Jeffrey D., WIDON, Jennifer, Implementação de Sistemas de Banco de Dados, 1ª ed. [Tradução: Vandenberg D. de Souza], Rio de Janeiro, CAMPUS, 2001.
SHAPIRO, Jeffrey R., SQL Server 2000, 1ª ed. [Tradução: Aldair José Coelho Corrêa da Silva], São Paulo, MAKRON Books, 2002.
Quest Software (www.quest.co)
Patrol (www.patrol.com)
Veritas (www.veritas.com)

sexta-feira, 8 de fevereiro de 2008

Linux - Programação C _ Bibliotecas Compartilhadas

PROGRAMAÇÃO

DESENVOLVENDO BIBLIOTECAS COMPARTILHADAS EM LINUX.

Por Ricardo Lima Caratti

Em programação, entende-se por bibliotecas, arquivos que contêm um conjunto de módulos ou membros de códigos pré-compilados reutilizáveis. Esses códigos podem ser usados por vários programas sem a necessidade de detalhes de sua implementação. A grande vantagem de usar uma biblioteca, é que uma vez fabricada, não será mais preciso compilar, bastando simplesmente liga-la ao programa desejado. Dessa forma, existe uma grande vantagem em usar bibliotecas, pois uma vez implementada ou adquirida de terceiros, o desenvolvedor pode se abstrair dos detalhes e concentrar-se somente no problema principal.

A figura abaixo esboça o uso de uma biblioteca




Note que “Meu Programa” necessitou usar uma função X e um procedimento Y. Entende-se por função, um procedimento ou uma rotina que retorna um valor. Sabendo que essas rotinas existem na biblioteca “Biblioteca”, para usa-las, basta fazer referência à biblioteca durante a compilação do programa principal.

Em Linux, pode-se desenvolver dois tipos de bibliotecas. A biblioteca de ligação estática e biblioteca de ligação dinâmica. As bibliotecas estáticas são ligadas ao programa e fazem parte do arquivo executável. Já as bibliotecas dinâmicas são ligadas em tempo de execução, ou seja, a ligação ocorre por demanda. Portanto, não fazem parte do programa principal, reduzindo assim, o tamanho do arquivo executável.

Optar pelo uso de bibliotecas estáticas ou dinâmicas depende muito do que se pretende. Em geral, pode-se obter o mesmo resultado usando uma ou outra técnica. Bibliotecas estáticas deixam o código executável mais livre da configuração do ambiente, ou seja, todo o código que o programa precisa para ser executado já se encontra no próprio executável. Ao contrário, quando se faz uso de bibliotecas compartilhadas, o programa é dividido em um módulo principal e em um ou mais módulos que serão ligados dinamicamente. Considerando que bibliotecas compartilhadas podem ser usadas por mais de um programa ao mesmo tempo, elas ocupam menos memória RAM, menos espaço em disco, menos recurso do sistema e finalmente fica mais simples fazer manutenção.

Resumindo, bibliotecas são arquivos que contêm módulos reutilizáveis pré-compilados que serão usados por desenvolvedores de aplicações. Elas podem ser classificadas em estáticas e compartilhadas. Ao optar por bibliotecas estáticas, ela passará a fazer parte do corpo do programa principal, liberando-o assim do ambiente de configuração do sistema. Ao contrário, bibliotecas compartilhadas ligam-se ao programa principal dinamicamente, ou seja, um módulo só será ligado ao programa principal se for solicitado. Com isso, bibliotecas compartilhadas consomem menos recursos do sistema operacional além de facilitarem a substituição de módulos defeituosos sem a necessidade de compilar novamente todos os outros módulos ou sistemas envolvidos.

Para ilustrar o desenvolvimento de bibliotecas compartilhadas, será utilizado o ambiente de desenvolvimento na linguagem C que vem com a própria distribuição Linux.

Será criado um procedimento que mostrará o resultado da soma de dois valores e uma função que dirá qual o maior valor.

Note pelo fonte a seguir, que não existe nada incomum no desenvolvimento das rotinas.

Fonte: MinhaLib.c


#include
#include
#include

/*

Dados dois argumentos inteiros, a e b, imprime a soma.

*/

void MinhaProcSoma( int a, int b)
{


int c;

c = a + b;

printf("\n a + b = %d \n", c);
}

/*

Dado dois argumentos inteiros, a e b, retorna o maior valor

*/

int MinhaFuncMaiorValor( int a, int b)

{

if ( a >= b)

return a;

else

return b;

}



É preciso agora tornar a função e o procedimento disponíveis para qualquer programa. Para tanto, é preciso compila-lo utilizando a seguinte linha de comando:

gcc -fPIC -c MinhaLib.c

Para obter mais detalhes sobre as opções de compilação do C da GNU utilize o comando man gcc. Um manual completo das opções do compilador será mostrado.


Após a compilação, um arquivo MinhaLib.o será gerado.

Até agora, tudo que se tem é um módulo compilado com um procedimento e uma função. Nessa forma, é possível utilizar MinhaLib.o como uma biblioteca estática. Bastando para isso, liga-la ao programa principal da seguinte forma:

gcc –o ProgPrincipal ProgPrincipal.c MinhaLib.o

Para fazer uso dos benefícios de bibliotecas compartilhadas, é preciso ir um pouco mais além. Para tanto, é preciso usar a seguinte linha de comando:

gcc -shared -Wl,-soname,libMinhaLib.so.1 -o libMinhaLib.so.1.0 MinhaLib.o

Apesar de não ser obrigatório iniciar o nome de uma biblioteca compartilhada com lib, é muito desejável, já que é o padrão de algumas ferramentas do Linux como veremos mais adiante. Pelo comando acima, será criada uma biblioteca com o nome de libMinhaLib.so.1.0. O sistema operacional irá reconhecê-la pelo nome de libMinhaLib.so.1. Isso também não é obrigatório, mas é bom usar esse padrão para ficar de acordo com as normas de desenvolvimento do Linux.

Na realidade o Linux usa o seguinte padrão para bibliotecas compartilhadas:

libaaa.so.b.c.ddd

onde:

libaaa.so é o nome da biblioteca;

b é um número que indicará a maior versão;

c é um número que indicará a menor versão;

ddd é um número que informa a “release”.

Uma vez desenvolvida as rotinas e criada a biblioteca compartilhada, é preciso publicá-la. Para tanto será preciso escolher um diretório onde suas bibliotecas ficarão. De preferência utilize /usr/local/lib. Utilizando um editor de texto de sua preferência, altere o arquivo /etc/ld.so.conf adicionando na última linha o diretório /usr/local/lib.

Mova a biblioteca compartilhada libMinhaLib.so.1.o para /usr/local/lib

mv libMinhaLib.so.1.o /usr/local/lib


em seguida execute o comando:


/sbin/ldconfig

o utilitário ldconf irá a todos os diretórios existentes referenciados em ld.so.conf e carregará todas as bibliotecas compartilhadas que iniciarem com lib, criando também um link que de acordo com o exemplo será libMinhaLib.so.1. Também será criada uma referência para cada biblioteca compartilhada em /etc/ld.so.cache. Isso permitirá que ela seja carregada toda vez que o sistema iniciar.

Após executar ldconfig, verifique no diretório /usr/local/lib os sequintes arquivos:


libMinhaLib.so.1 (Link criado pelo ldconfig);
libMinhaLib.so.1.o a biblioteca criada por você.


Testando a biblioteca:

Programa de Teste (TestaProc.c):

#include

#include

int main()
{
void *descritor;
void (*PonteiroParaMinhaProcSoma)( int a, int b);

int (*PonteiroParaMinhaFuncMaiorValor( int a, int b);

int x, y, MaiorValor;

x = 10; /* Somente para exemplo */
y = 11; /* Somente para exemplo */

/* Abre a biblioteca compartilhada */
if ( descritor = dlopen("MinhaLib.so.1.0",RTLD_LAZY))
{
PonteiroParaMinhaProcSoma = dlsym(descritor,"MinhaProcSomal");

PonteiroParaMinhaFuncMaiorValor = dlsym(descritor,”MinhaFuncMaiorValor”);

/* Chamada a MinhaProcSoma */

(*PonteiroParaMinhaProcSoma)( 2, 4 );
(*PonteiroParaMinhaProcSoma)( x, y );

/* Chamada a MinhaFuncMaiorValor */

MaiorValor = (*PonteiroParaMinhaFuncMaiorValor)(x,y);

printf(“\nO Maior valor é: %d”, MaiorValor);

}
else

{
printf("\nErro ao tentar usar a biblioteca dinâmica\n");

printf(“\n%s\n”,dlerror() );

return 0;
}

Observações:

#include

Declarações das funções para manipulação de bibliotecas dinâmicas

dlopen(const char*filename, int flag)

Carrega uma biblioteca Compartilhada

void * dlsym(void *handle, char *symbol)

Obtem o endereço do procedimento dentro
da biblioteca compartilhada

const char *dlerror()

Retorna uma string contendo o erro ou NULL se tudo OK

int dlclose(void *handle)

Fecha a biblioteca


Compile esse programa com:

gcc -o TesteProc TesteProc.c -ldl

Para executar faça:

./TestaProc

O exemplo mostrará o seguinte resultado:

a + b = 6
a + b = 21

O Maior valor é: 11

Para efeito prático, altere o procedimento MinhaProcSoma em MinhaLib.c da seguinte forma:

c = b - a;

printf("\n b - a = %d \n", c);

Execute os passos a seguir:

gcc -fPIC -c MinhaLib.c

gcc -shared -Wl,-soname,libMinhaLib.so.1 -o libMinhaLib.so.1.0 MinhaLib.o

mv libMinhaLib.so.1.o /usr/local/lib

Execute novamente o programa TestaProc da seguinte forma:

./TestaProc

Resultado:

b - a = 2
b - a = 1

O Maior valor é: 11

Note que não foi preciso compilar novamente o programa TestaProc. Nesse caso, a ligação à biblioteca alterada MinhaLib, foi efetuada em tempo de execução.

Concluindo, o Linux bem como outros ambientes Unix facilitam o uso e o desenvolvimento de bibliotecas compartilhadas. Dentre as vantagens em usar essas bibliotecas, destaca-se a facilidade de manutenção de sistemas, considerando é claro, que para tanto, basta trocar o módulo defeituoso sem a necessidade de re-compilar todos os outros módulos que o compõe.


Referências Bibliograficas:

WALL, WATSON, AND WHITIS. Linux Programming. SAMS, 1999

BARKAKATI, NABA. Red Hat Linux Secrets, Info World – IDG Books, 2nd Edition, 1999