Ir para conteúdo
  • Cadastre-se

dev botao

Uso da biblioteca ACBrLib MT com múltiplas Threads


Ver Solução Respondido por antonio.carlos,
  • Este tópico foi criado há 365 dias atrás.
  • Talvez seja melhor você criar um NOVO TÓPICO do que postar uma resposta aqui.

Recommended Posts

  • Membros Pro
Postado

Olá!

Iniciei este tópico no Discord, mas fui orientado a abri-lo aqui no Fórum também.

Minha intenção é criar um serviço em container Linux (uso podman, mas poderia ser docker também), usando xvfb, para suportar uma aplicação Web multiempresa. Fiz testes com containers com base Debian, Ubuntu e Archlinux, tendo encontrado o mesmo problema em todos eles. 

Estou com dificuldades no uso da ACBrLib versão MT quando tento instanciar a biblioteca em threads diferentes. Se uso a biblioteca, versão MT, em um programa ST (singlethread), consigo obter tantas instâncias quanto desejar, cada qual recebendo um handle próprio. No entanto, se tento criar instâncias em threads distintas, recebo um SIGSEGV. 

Dado o problema com os containers, optei por fazer os testes em uma máquina com Linux instalado nativamente. Uso a versão MT da biblioteca em ambiente Linux com desktop gráfico Gnome. Minha distribuição é a Manjaro Linux, kernel versão 64 bits. A linguagem de desenvolvimento é Rust, mas também fiz testes sem sucesso com a linguagem C. Importante observar que os mesmos testes, sem sucesso, também foram realizados em uma máquina com Ubuntu Desktop 22.04 64 bits instalado, mas desta feita em uma máquina virtual.

Para reprodução do meu problema, anexo o código fonte de um pequeno programa em linguagem C. 

Instruções para execução do programa:

  1. Instalar a versão MT da libacbrcte64.so no sistema 
  2. Alterar os defines no código fonte para definir a localização desta biblioteca caso use um local diferente 
  3. Compilar e executar o  código com : gcc -std=c11 -Wall -Werror -lacbrcte64 main.c -o main && ./main

Ensaios podem ser feitos alterando-se os seguintes defines no código fonte:

  • NUMERO_DE_THREADS
  • NUMERO_DE_INSTANCIAS

Observem que, quando definimos somente uma thread, podemos criar tantas instâncias quantas quisermos. No entanto, se indicamos mais de uma thread, recebemos um SIGSEGV assim que a função CTE_Inicializar é chamada.

Isto posto, seria muito bom termos um exemplo de uso da biblioteca, versão MT, em um programa também MT.

Antecipadamente lhes agradeço pela atenção e ajuda!

[]s,

Eduardo Herediamain.c

Exemplo com 1 thread e 5 instancias.png

Exemplo com 2 threads e 5 instâncias por thread.png

  • Administradores
Postado

Boa tarde,

Assim que houver um posicionamento do assunto, será retornado aqui.

At.

Consultora SAC ACBr

Juliana Tamizou

Gerente de Projetos ACBr / Diretora de Marketing AFRAC
Ajude o Projeto ACBr crescer - Seja Pro

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil


Participe de nosso canal no Discord e fique ainda mais próximo da Comunidade !!

  • 3 semanas depois ...
  • Administradores
Postado

Bom dia,
Nas ultimas semanas nosso time da Lib esteve atuando intensamente no projeto da ACbrLibNFSe a qual tem sido um sucesso...

Nos próximos dias devemos focar exatamente neste caso.

At.

Consultora SAC ACBr

Juliana Tamizou

Gerente de Projetos ACBr / Diretora de Marketing AFRAC
Ajude o Projeto ACBr crescer - Seja Pro

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Projeto ACBr - A maior comunidade Open Source de Automação Comercial do Brasil


Participe de nosso canal no Discord e fique ainda mais próximo da Comunidade !!

  • 5 meses depois ...
  • Consultores
  • Solution
Postado

Falha de segmentação SIGSEGV é comum de erro em programação que ocorre quando um programa tenta acessar uma parte da memória que não tem permissão para acessar. Isso geralmente ocorre devido a bugs no código, como acessar um ponteiro nulo, acessar uma área de memória liberada ou escrever além dos limites de um array.

A linguagem de programação que você utiliza, não é minha linguagem nativa, então tive que fazer algumas pesquisas.. para entender a linguagem e tentar te ajudar..

Veja se essas opções não te ajuda em relação uso da ACBrLib MultiThread.

Adicione Sincronização:
Tente adicionar mutexes (travas) ao redor do código que está usando a biblioteca ACBrLibCTe. Isso pode ajudar a evitar condições de corrida entre as threads,

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>

#define NUMERO_DE_THREADS 1
#define NUMERO_DE_INSTANCIAS 5
#define ACBRLIBCTE "/usr/local/lib/libacbrcte64.so"

typedef int (*inicializar_t)(u_int64_t *, char *, char *);
typedef int (*finalizar_t)(u_int64_t);

inicializar_t inicializar;
finalizar_t finalizar;

// Mutex para sincronização
pthread_mutex_t acbrMutex = PTHREAD_MUTEX_INITIALIZER;

void* run(void *);

int main() {
  // Carrega a biblioteca ACBrLibCTe
  void *lib = dlopen(ACBRLIBCTE, RTLD_LAZY);
  if (!lib) {
    fprintf(stderr, "Erro ao carregar a biblioteca\n\n");
    exit(1);
  }

  // Atualiza os ponteiros para as funções que serão testadas na ACBrLibCte
  inicializar = (inicializar_t)dlsym(lib, "CTE_Inicializar");
  finalizar = (finalizar_t)dlsym(lib, "CTE_Finalizar");

  // Cria vetor com as threads criadas
  pthread_t threads[NUMERO_DE_THREADS];

  for(int i=0; i<NUMERO_DE_THREADS; i++) {
    // Define o número da Thread para mensagem de log
    int *nr_thread = malloc(sizeof(int));
    *nr_thread = i;
    // Cria a thread e inicia execução
    pthread_create(&threads[i], NULL, run, (void *) nr_thread);
  }

  // Aguarda a finalização de todas as threads
  for(int i=0; i<NUMERO_DE_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }

  // Encerra o uso da biblioteca
  dlclose(lib);

  // Destroi o mutex
  pthread_mutex_destroy(&acbrMutex);
}

void * run(void *p) {
  int nr_thread = *((int *) p);
  
  u_int64_t handle[NUMERO_DE_INSTANCIAS];

  char *senha = calloc(64, sizeof(char));
  strcpy(senha, "senha");

  // Cria instâncias da biblioteca ACBrLibCTe
  for (int i = 0; i < NUMERO_DE_INSTANCIAS; i++) {
    pthread_mutex_lock(&acbrMutex); // Trava o mutex antes de acessar a biblioteca
    char *arquivo = calloc(64, sizeof(char));
    sprintf(arquivo, "acbrlib-%d.ini", i);
    int retorno = inicializar(&handle[i], arquivo, senha);
    printf("(Thread #%2d - Instância #%2d) Função <<<CTE_Inicializar>>> [Retorno da Biblioteca: %d] [Handle retornado : %lu]\n", nr_thread, i, retorno, handle[i]);
    pthread_mutex_unlock(&acbrMutex); // Destrava o mutex após acessar a biblioteca
  }

  // Finaliza as instâncias da biblioteca ACBrLibCTe
  for (int i = 0; i < NUMERO_DE_INSTANCIAS; i++) {
    pthread_mutex_lock(&acbrMutex);
    int retorno = finalizar(handle[i]);
    printf("(Thread #%2d - Instância #%2d) Função <<<CTE_Finalizar  >>> [Retorno da Biblioteca: %d] [Handle finalizado: %lu]\n", nr_thread, i, retorno, handle[i]);
    pthread_mutex_unlock(&acbrMutex);
  }

  // Libera o parâmetros 
  free(p);

  return NULL;
}


Inicialização Global:
Inicie a biblioteca uma vez no início do programa, antes de criar qualquer thread, e compartilhe o handle entre as threads. Isso evita a necessidade de inicialização concorrente. Aqui está um exemplo:

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>

#define NUMERO_DE_THREADS 1
#define NUMERO_DE_INSTANCIAS 5
#define ACBRLIBCTE "/usr/local/lib/libacbrcte64.so"

typedef int (*inicializar_t)(u_int64_t *, char *, char *);
typedef int (*finalizar_t)(u_int64_t);

inicializar_t inicializar;
finalizar_t finalizar;

u_int64_t globalHandle;

void* run(void *);

int main() {
  // Carrega a biblioteca ACBrLibCTe
  void *lib = dlopen(ACBRLIBCTE, RTLD_LAZY);
  if (!lib) {
    fprintf(stderr, "Erro ao carregar a biblioteca\n\n");
    exit(1);
  }

  // Atualiza os ponteiros para as funções que serão testadas na ACBrLibCte
  inicializar = (inicializar_t)dlsym(lib, "CTE_Inicializar");
  finalizar = (finalizar_t)dlsym(lib, "CTE_Finalizar");

  // Inicializa a biblioteca globalmente
  char *senha = calloc(64, sizeof(char));
  strcpy(senha, "senha");
  char *arquivo = "acbrlib-global.ini";
  int retorno = inicializar(&globalHandle, arquivo, senha);

  // Cria vetor com as threads criadas
  pthread_t threads[NUMERO_DE_THREADS];

  for(int i=0; i<NUMERO_DE_THREADS; i++) {
    // Define o número da Thread para mensagem de log
    int *nr_thread = malloc(sizeof(int));
    *nr_thread = i;
    // Cria a thread e inicia execução
    pthread_create(&threads[i], NULL, run, (void *) nr_thread);
  }

  // Aguarda a finalização de todas as threads
  for(int i=0; i<NUMERO_DE_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }

  // Finaliza a instância global da biblioteca
  retorno = finalizar(globalHandle);
  printf("(Global) Função <<<CTE_Finalizar  >>> [Retorno da Biblioteca: %d] [Handle finalizado: %lu]\n", retorno, globalHandle);

  // Encerra o uso da biblioteca
  dlclose(lib);
}

void * run(void *p) {
  int nr_thread = *((int *) p);
  
  u_int64_t handle[NUMERO_DE_INSTANCIAS];

  char *senha = calloc(64, sizeof(char));
  strcpy(senha, "senha");

  // Cria instâncias da biblioteca ACBrLibCTe
  for (int i = 0; i < NUMERO_DE_INSTANCIAS; i++) {
    char *arquivo = calloc(64, sizeof(char));
    sprintf(arquivo, "acbrlib-%d.ini", i);
    int retorno = inicializar(&handle[i], arquivo, senha);
    printf("(Thread #%2d - Instância #%2d) Função <<<CTE_Inicializar>>> [Retorno da Biblioteca: %d] [Handle retornado : %lu]\n", nr_thread, i, retorno, handle[i]);
  }

  // Finaliza as instâncias da biblioteca ACBrLibCTe
  for (int i = 0; i < NUMERO_DE_INSTANCIAS; i++) {
    int retorno = finalizar(handle[i]);
    printf("(Thread #%2d - Instância #%2d) Função <<<CTE_Finalizar  >>> [Retorno da Biblioteca: %d] [Handle finalizado: %lu]\n", nr_thread, i, retorno, handle[i]);
  }

  // Libera o parâmetros 
  free(p);

  return NULL;
}


Como você deve conhecer a linguagem que esta utilizando, acredito que estes dois exemplos possam te ajudar.. 

  • Curtir 1
×
×
  • Criar Novo...

Informação Importante

Colocamos cookies em seu dispositivo para ajudar a tornar este site melhor. Você pode ajustar suas configurações de cookies, caso contrário, assumiremos que você está bem para continuar.