Avançar para a área de conteúdo

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Todas as informações enviadas são seguras.

  • Fechar [x]

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

Todas as informações enviadas são seguras.

  • Fechar [x]

Desenvolvimento de comunicação simultânea de alto desempenho no UNIX utilizando a estrutura de biblioteca ACE

Arpan Sen, Technical lead, Synapti Computer Aided Design Pvt Ltd
Arpan Sen é o principal engenheiro trabalhando no desenvolvimento de software no segmento de automação de projeto eletrônico. Ele trabalhou com diversos recursos do UNIX, incluindo o Solaris, SunOS, HP-UX e IRIX, assim como com o Linux e o Microsoft Windows por vários anos. Ele possui um grande interesse em técnicas de otimização de desempenho de software, teoria dos grafos e computação paralela. Arpan possui pós-graduação em sistemas de software. É possível entrar em contato com ele em arpan@syncad.com.

Resumo:  O conjunto de ferramentas de código aberto ACE ajuda os desenvolvedores a criar aplicativos de multiencadeamento móveis e poderosos. Observe algumas das maneiras que podem ser utilizadas para criar aplicativos que usem os encadeamentos do ACE.

Data:  30/Jun/2009
Nível:  Intermediário
Atividade:  851 visualizações
Comentários:  


O Adaptive Communication Environment (ACE) é uma estrutura de código aberto orientada a objeto de alto desempenho e C++ uma biblioteca de classe que simplifica o desenvolvimento de aplicativos de rede. O conjunto de ferramentas ACE é uma combinação de uma camada do sistema operacional e uma coleção de C++ fachadas que encapsulam a rede API. Este artigo mostra como projetar aplicativos de rede orientados a objeto, simultâneos e de alto desempenho usando os encadeamentos ACE. Para obter uma descrição completa do ACE, incluindo como efetuar o download e instalar o conjunto de ferramentas, consulte Recursos.

Classes ACE para criação e gerenciamento de encadeamentos

As classes a seguir estão envolvidas na criação e gerenciamento de múltiplos encadeamentos dentro de um processo:

  • ACE_Thread_Manager: Esta é a classe principal responsável pela criação, gerenciamento e sincronização dos encadeamentos. Todos os sistemas operacionais possuem suas próprias sutilezas na manipulação dos encadeamentos: Esta classe do wrapper deixa estas peculiaridades opacas para o desenvolvedor de aplicativos.
  • ACE_Sched_Params: Esta classe é utilizada para gerenciar a prioridade do planejamento dos encadeamentos individuais, que é definida como parte do cabeçalho ace/Sched_Params.h na distribuição da origem ACE. As políticas de planejamento variam e podem ser round robin ou primeiro a chegar, primeiro a ser servido.
  • ACE_TSS: O uso de variáveis globais em um aplicativo multiencadeado é um problema de sincronização. A classe ACE_TSS oferece um padrão de armazenamento específico do encadeamento, fornecendo a abstração de dados que são logicamente globais para o programa, mas na realidade são privados para cada encadeamento. A classe ACE_TSS fornece o método operator(), o que, por sua vez, oferece os dados específicos do encadeamento.

Entendendo a classe do gerente de encadeamento

As APIs de encadeamento de sistemas operacionais nativos não são móveis: Há diferenças sintáticas e semânticas. Por exemplo, os métodos ® pthread_create() do UNIX e o ® CreateThread() do Windows criam um encadeamento, mas com diferenças sintáticas. A classe ACE_Thread_Manager vem com os seguintes recursos:

  • Ela pode criar um ou mais encadeamentos, cada um deles executando sua própria função designada.
  • Ela pode gerenciar os encadeamentos relacionados como uma coleção coesa, conhecida como um grupo de encadeamentos.
  • Ela gerencia a prioridade de planejamento dos encadeamentos individuais.
  • Ela permite a sincronização entre os encadeamentos.
  • Ela pode alterar atributos do encadeamento como o tamanho de pilha.

Os métodos notáveis da classe ACE_Thread_Manager são descritos na Tabela 1.


Tabela 1. Métodos da classe ACE_Thread_Manager
Nome do métodoDescrição
instanceA classe ACE_Thread_Manager é um singleton, este método é utilizado para acessar a cópia exclusiva do Thread Manager.
spawnEste método cria um novo encadeamento, um argumento de entrada aplicado a ele sendo o ponteiro de função C/C++ que faz o trabalho designado do aplicativo.
exitEste método sai de um encadeamento e libera todos os recursos do encadeamento.
spawn_nEste método cria múltiplos encadeamentos que pertencem ao mesmo grupo de encadeamento.
closeEste método encerra e libera os recursos de todos os encadeamentos criados.
suspendDeterminado o ID do encadeamento, o gerente de encadeamento o suspende.
resumeO gerente de encadeamento retoma o encadeamento anteriormente suspenso.

Variações no uso da classe ACE_Thread_Manager

É possível utilizar a classe ACE_Thread_Manager como um singleton ou criar múltiplas instanciações da classe. Para o singleton, é possível usar uma chamada para o método instance para obter acesso. Em situações em que é necessário gerenciar múltiplos grupos de encadeamento, é útil possuir diferentes classes de gerente de encadeamento, cada uma controlando seu próprio conjunto de encaminhamentos.

Observe o exemplo na Lista 1, que cria um encadeamento.


Lista 1. Criando um encadeamento usando a classe ACE_Thread_Manager
	
#include "ace/Thread_Manager.h"
#include <iostream>

void thread_start(void* arg)
{
  std::cout << "Running thread..\n";
}

int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
{
  ACE_Thread_Manager::instance()->spawn((ACE_THR_FUNC)thread_start);
  return 0;
}

A Lista 2 mostra o protótipo para o método spawn(), originado do ace/Thread_Manager.h.


Lista 2. O protótipo para o método de criação do ACE_Thread_Manager::
	
  int spawn (ACE_THR_FUNC func,
             void *arg = 0,
             long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED,
             ACE_thread_t *t_id = 0,
             ACE_hthread_t *t_handle = 0,
             long priority = ACE_DEFAULT_THREAD_PRIORITY,
             int grp_id = -1,
             void *stack = 0,
             size_t stack_size = ACE_DEFAULT_THREAD_STACKSIZE,
             const char** thr_name = 0);

O número de argumentos absolutos necessários para criar apenas um encadeamento básico podem parecer impressionantes para os usuários na primeira utilização, então, observemos melhor os argumentos individuais e por que eles são necessários:

  • ACE_THR_FUNC func: Esta função é solicitada quando o encadeamento é criado.
  • void* arg:Um argumento para a função solicitada quando o encadeamento é criado, void* significa que os usuários estão livres para passar em qualquer tipo de dado específico do aplicativo ou ainda unir múltiplos argumentos em um único dado usando uma estrutura.
  • long flags: Várias propriedades do encadeamento criado são definidas usando a variável flags. Os atributos individuais são bitwise ou -ed. A Tabela 2 mostra alguns dos atributos.
  • ACE_thread_t *t_id: Use esta função para acessar o ID do encadeamento criado. Cada encadeamento possui um ID único.
  • long priority: Esta é a prioridade com que os encadeamentos são criados.
  • int grp_id: Caso seja fornecido, este argumento indica se o encadeamento deve fazer parte de algum grupo de encadeamento existente. Caso contrário, caso o -1 é aceito como o argumento, um novo grupo de encadeamento é criado e o encadeamento criado é adicionado a ele.
  • void* stack: Este é o ponteiro para a área de pilha pré-alocada. Se 0 for fornecido como o argumento, é solicitado que o sistema operacional forneça a área de pilha do encadeamento criado.
  • size_t stack_size: Este argumento indica o tamanho da pilha do encadeamento em bytes. Se 0 for fornecido como o argumento para o stack pointer (item 7), é solicitado que o sistema operacional indique uma área com o tamanho stack_size.
  • const char** thr_name: Este argumento é relevante apenas em plataformas como o VxWorks que possuem a capacidade de nomear os encadeamentos. Ele é ignorado para a maioria dos propósitos nos sistemas UNIX.

Tabela 2. Propriedades do encadeamento e suas descrições
Sinalizador de criação de encadeamentoDescrição
THR_CANCEL_DISABLENão permite que o encadeamento seja cancelado.
THR_CANCEL_ENABLEPermite que o encadeamento seja cancelado.
THR_DETACHEDCria um encadeamento assíncrono. O status de saída do encadeamento não poderia estar disponível em nenhum outro encadeamento. Os recursos do encadeamento são exigidos pelo sistema operacional sempre que o encadeamento for terminado.
THR_JOINABLEPermite que o status de saída do novo encadeamento seja disponibilizado para outros encadeamentos. Este também é o atributo padrão nos encadeamentos ACE criados. Quando este tipo de encadeamento expira, os recursos não são exigidos pelo sistema operacional até que algum outro encadeamento una-se a ele.
THR_NEW_LWPCria um encadeamento do nível do kernel explicito (como oposição ao encadeamento do nível do usuário).
THR_SUSPENDEDCria um novo encadeamento no estado suspenso.

A Lista 3 fornece um exemplo que cria múltiplos encadeamentos usando o método spawn_n da classe do gerente de encadeamento.


Lista 3. Criando múltiplos encadeamentos usando a classe ACE_Thread_Manager
	
#include "ace/Thread_Manager.h"
#include <iostream>

void print (void* args)
{
  int id = ACE_Thread_Manager::instance()->thr_self();
  std::cout << "Thread Id: " << id << std::endl;
}

int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
{
  ACE_Thread_Manager::instance()->spawn_n(
      4, (ACE_THR_FUNC) print, 0, THR_JOINABLE | THR_NEW_LWP);

  ACE_Thread_Manager::instance()->wait();
  return 0;
}


Mecanismo alternativo de criação de encadeamento no ACE

Esta seção trata de um esquema de gerenciamento/criação alternativo de encadeamento no ACE, o esquema que não precisa do nível explicito de controle detalhado do gerente de encadeamento. Por padrão, cada processo é criado com um único encadeamento que inicia e é encerrado com a função main . Quaisquer encadeamentos extras precisam da criação explícita. Uma maneira alternativa de criar os encadeamentos é com a criação de uma subclasse da classe ACE_Task_Base pré-definida, então substituir o método svc() . O novo encadeamento é iniciado no método svc() e é encerrado quando o método svc() retorna. Antes de prosseguir com a explicação, observe a fonte mostrada na Lista 4.


Lista 4. Criando um encadeamento usando o ACE_Task_Base::svc
	
#include “ace/Task.h”

class Thread_1 : public ACE_Task_Base { 
  public: 
    virtual int svc( ) { 
       std::cout << “In child’s thread\n”;
       return 0;
    }
 };

int main ( )
{ 
   Thread_1 th1;
   th1.activate(THR_NEW_LWP|THR_JOINABLE);
   th1.wait();
   return 0;
}

O comportamento específico do aplicativo do encadeamento está codificado no método svc() . Para executar o encadeamento, o método activate() (declarado e definido como parte da classe ACE_Task_Base ) é solicitado. Quando o encadeamento estiver ativado, a função main() espera que o encaminhamento filho conclua a execução. É isso que o método wait() tenta obter: O encadeamento principal é bloqueado até que o Thread_1 seja completado. Esta espera é um recurso necessário, caso contrário, o encadeamento principal poderia planejar o encadeamento filho e criado uma saída. O tempo de execução C , ao observar a saída do encadeamento principal, deveria destruir todos os encaminhamentos filho, especificamente, o encadeamento filho provavelmente nunca poderia ter sido planejado ou executado.

Entendendo a classe ACE_Task_Base mais detalhadamente

Aqui há um exame relativamente detalhado em alguns dos métodos no ACE_Task_Base.

A Lista 5 mostra o protótipo do método activate() .


Lista 5. O protótipo do método ACE_Task_Base::activate
	
virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED,
                        int n_threads = 1,
                        int force_active = 0,
                        long priority = ACE_DEFAULT_THREAD_PRIORITY,
                        int grp_id = -1,
                        ACE_Task_Base *task = 0,
                        ACE_hthread_t thread_handles[ ] = 0,
                        void *stack[ ] = 0,
                        size_t stack_size[ ] = 0,
                        ACE_thread_t thread_ids[ ] = 0,
                        const char* thr_name[ ] = 0);

É possível utilizar o método activate() para criar um ou mais encadeamentos do controle, cada um dos quais chama o mesmo método svc() , e todos sendo executados com a mesma prioridade com o mesmo ID de grupo. Eis uma breve descrição de alguns dos argumentos de entrada:

  • long flags: Consulte a Tabela 2.
  • int n_threads: Cria o número de encadeamentos especificados pelo n_threads.
  • int force_active: Se este sinalizador for True e houver encadeamentos existentes criados pela tarefa, então todos os encadeamentos recentemente criados devem compartilhar o ID do grupo dos anteriormente criados e ignorar o valor conforme passado para o método activate() .
  • long priority: Este argumento designa uma prioridade para o encaminhamento ou coleção de encaminhamentos. Os valores de prioridade de planejamento são específicos do sistema operacional e é uma aposta segura para o valor padrão a ser seguido do ACE_DEFAULT_THREAD_PRIORITY.
  • ACE_hthread_t thread_handles: Se thread_handles != 0, então, após a criação dos n encadeamentos, este array será designado para os identificadores do encadeamento individual.
  • void* stack: Caso seja especificado, este argumento indica um array dos ponteiros para a base das pilhas para os encaminhamentos individuais.
  • size_t stack_size: Caso seja especificado, este argumento indica um array dos números inteiros indicando o tamanho das pilhas dos encaminhamentos individuais.
  • ACE_thread_t thread_ids: Se thread_ids != 0, presume-se que é um array que suspenderá os IDs dos n encadeamentos criados recentemente.

A Lista 6 mostra algumas outras rotinas úteis na classe ACE_Task_Base .


Lista 6. Rotinas diversas do ACE_Task_Base
	
// Bloqueia o encadeamento principal até que todos os 
	encadeamentos desta tarefa sejam concluídos
virtual int wait (void);

// Suspende uma tarefa
virtual int suspend (void);

// Continua a tarefa suspensa.
virtual int resume (void);

// Obtém o número de encadeamentos ativos em uma tarefa
size_t thread_count (void) const;

// Retorna o id do último encadeamento cuja saída fez com que a contagem de encadeamentos 
// desta tarefa fosse 0. Um status de retorno zero significa que o resultado é 
// desconhecido. Talvez não haja encadeamentos planejados.
ACE_thread_t last_thread (void) const;

Para criar um encadeamento em um estado suspenso (em oposição a uma suspensão explicitamente utilizando a chamada de método suspend() ), é necessário passar o sinalizador THR_SUSPENDED para o método activate() . É possível continuar o encadeamento ao chamar o método resume() , conforme mostrado na Lista 7.


Lista 7. Suspensão e continuação dos encadeamentos
	
Thread_1 th1;
th1.activate(THR_NEW_LWP|THR_JOINABLE|THR_SUSPENDED);
…// código no encadeamento principal
th1.resume();
…// o código continua no encadeamento principal


Uma outra observação dos sinalizadores de encadeamento

São possíveis dois tipos de encadeamento: encadeamentos do nível do kernel e encadeamentos do nível de usuário. Se o método activate() for chamado sem nenhum argumento, o padrão é criar um encadeamento do nível do kernel. Os encadeamentos do nível do kernel interagem diretamente com o sistema operacional e são planejados pelo planejador do nível do kernel. Em contrapartida, os encadeamentos do nível do usuário operam no escopo do processo e são encadeamentos do nível do kernel "designados" de acordo com o necessário para completar algumas tarefas. O sinalizador THR_NEW_LWP, que é o argumento padrão para o método activate() , sempre garante que o novo encadeamento criado seja um encadeamento do nível do kernel.

Ganchos do encadeamento

O ACE fornece um gancho de inicialização global do encadeamento que permite que o usuário realize qualquer tipo de operação que seja globalmente aplicável para todos os encadeamentos. Para criar um gancho de inicialização, é necessário criar uma subclasse da classe pré-definida ACE_Thread_Hook e fornecer a definição para o método start() . O método start() aceita dois argumentos: um ponteiro para uma função definida pelo usuário e uma void*, que é aceito por essa função definida pelo usuário. Para registrar o gancho é necessário chamar o método estático ACE_Thread_Hook::thread_hook, conforme mostrado na Lista 8.


Lista 8. Usando ganchos de encadeamento globais
	
#include "ace/Task.h"
#include "ace/Thread_Hook.h"
#include <iostream>

class globalHook : public ACE_Thread_Hook {
  public:
    virtual ACE_THR_FUNC_RETURN start (ACE_THR_FUNC func, void* arg) {
        std::cout << "In created thread\n";
        (*func)(arg);
    }
};

class Thread_1 : public ACE_Task_Base {
  public:
    virtual int svc( ) {
       std::cout << "In child's thread\n";
       return 0;
    }
 };


int ACE_TMAIN (int argc, ACE_TCHAR* argv[])
{
  globalHook g;
  ACE_Thread_Hook::thread_hook(&g);
  Thread_1 th1;
  th1.activate();
  th1.wait();
  return 0;
}

Observe que o ponteiro ACE_THR_FUNC que é automaticamente aceito pelo gancho de inicialização é igual à função que poderia ter sido chamada quando o método activate() do encadeamento é realizado. Os resultados do código acima são as mensagens:

In created thread
In child’s thread


Conclusão

Este artigo fez uma primeira observação sobre a criação e o gerenciamento dos encadeamentos utilizando a estrutura ACE. A estrutura ACE possui vários outros recursos úteis, como mutexes, blocos de segurança para sincronização, memória compartilhada e serviços de rede. Consulte Recursos para obter detalhes.


Recursos

Aprender

  • Compilação e Instalação do ACE: Saiba como compilar e instalar a biblioteca ACE.

  • Suporte ACE: Obtenha o suporte comercial para a biblioteca ACE.

  • AIX e UNIX: A visita à zona do developerWorks AIX e UNIX oferece fartas informações relacionadas a todos os aspectos da administração de sistemas AIX e à expansão de suas qualificações em UNIX.

  • Novo no AIX e UNIX? Visite a página Novo no AIX e UNIX para saber mais.

  • Livraria de tecnologia: Pesquise por livros sobre este e outros tópicos técnicos.

Obter produtos e tecnologias

  • Estrutura ACE: Efetue o download da estrutura de biblioteca ACE.

Discutir

Sobre o autor

Arpan Sen é o principal engenheiro trabalhando no desenvolvimento de software no segmento de automação de projeto eletrônico. Ele trabalhou com diversos recursos do UNIX, incluindo o Solaris, SunOS, HP-UX e IRIX, assim como com o Linux e o Microsoft Windows por vários anos. Ele possui um grande interesse em técnicas de otimização de desempenho de software, teoria dos grafos e computação paralela. Arpan possui pós-graduação em sistemas de software. É possível entrar em contato com ele em arpan@syncad.com.

Ajuda para Relatar Abuso

Relatar abuso

Obrigado. Esta entrada foi sinalizada para atenção do moderador.


Ajuda para Relatar Abuso

Relatar abuso

Falha no envio do Relatório de abuso. Tente novamente mais tarde.


developerWorks: Registre-se


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Na primeira vez que você efetua sign in no developerWorks, um perfil é criado para você. Informações selecionadas do seu perfil developerWorks são exibidas ao público, mas você pode editá-las a qualquer momento. Seu primeiro nome, sobrenome (a menos que escolha ocultá-los), e seu nome de exibição acompanharão o conteúdo que postar.

Selecione seu nome de exibição

Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

(Deve possuir de 3 a 31 caracteres.)


Ao clicar em Enviar, você concorda com os termos de uso do developerWorks.

 


Classificar este artigo

Comentários

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre
ArticleID=412525
ArticleTitle=Desenvolvimento de comunicação simultânea de alto desempenho no UNIX utilizando a estrutura de biblioteca ACE
publish-date=06302009
author1-email=arpansen@gmail.com
author1-email-cc=mmccrary@us.ibm.com

Conheça a IBM da sua cidade

Virtual Branch Office Brasil

A IBM está mais perto do que você imagina!


Tags

Help
Use o campo de pesquisa para encontrar todos os tipos de conteúdo no My developerWorks com essa tag.

Use a barra de rolagem para ver mais ou menos tags.

Tags populares mostra as principais tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Minhas tags mostra suas tags para esta zona de conteúdo em particular (por exemplo, Java technology, Linux, WebSphere).

Use o campo de pesquisa para localizar todos os tipos de conteúdo no Meu developerWorks com essa tag. Tags populares mostra as tags principais para essa zona de conteúdo particular (por exemplo, tecnologia Java, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere). Minhas tags mostra as suas tags para essa zona de conteúdo em particular (por exemplo, tecnologia Java, Linux, WebSphere).