Pular para o conteúdo principal

Postagem em destaque

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️

🚀 Oferecendo Serviços Remotos de Desenvolvedor AdvPL e Mais 🖥️ Olá pessoal, Espero que este post encontre todos vocês bem! É com grande entusiasmo que compartilho que estou expandindo meus serviços como Desenvolvedor AdvPL para novos desafios e colaborações. Com mais de duas décadas de experiência sólida, minha jornada profissional tem sido enriquecedora, com a oportunidade de participar de projetos empolgantes ao longo dos anos. Agora, estou ansioso para trazer minha experiência e habilidades para novas equipes e projetos, trabalhando de forma remota. Minha expertise abrange não apenas AdvPL, mas também outras tecnologias-chave, incluindo JS, SQL, Infraestrutura e Otimização de Processos. Acredito que essa combinação de conhecimentos me permite oferecer soluções abrangentes e eficazes para uma variedade de necessidades de desenvolvimento. Acredito que a tecnologia tem o poder de transformar negócios e impulsionar o sucesso, e estou comprometido em ajudar meus clientes a alcançar seu

Protheus :: Variáveis Globais, Threads e outros bichos

Falarei hoje sobre Variáveis Globais (Global Variables) e Threads. Usarei como primeiro exemplo o programa u_sudoku.prg depois escreverei dois estudos de caso.

Conhecemos as variáveis de escopo Public, Private, Static e Local. As variáveis Public e Private podem ser declaradas em qualquer parte do programa. As variáveis Static podem ser externas ou internas. Externas, quando declaradas fora de qualquer Function ou Procedure e no cabeçalho do programa em que estão sendo declaradas. E, internas, quando atreladas à uma Procedure ou Function e logo após a declaração das variáveis de escopo Local. Já as variáveis de escopo Local  apenas depois da declaração da Procedure ou Function e antes de qualquer procedimento.

As variáveis Private tem um tratamento especial, elas podem ser declaradas de três formas:

Explicitamente:

Private nPrivateVar

Implicitamente, atribuindo-se um valor a uma variável não declarada anteriormente, como por exemplo:

IF ( Type("nPrivateNaoDeclarada") == "U" )
nPrivateNaoDeclarada := "Terei o escopo Private e a partir desse ponto todo mundo me vê"
ENDIF

Ou, ainda, através da função _SetOwnerPrvt( cVar , uValue ) uma grande sacada da microsiga. _SetOwnerPrvt() é interessante pois a Private declarada à partir dela pode ser acessada pela função um nível acima de onde foi declarada. Veja como é interessante.

User Function Foo()

Private nPrvtFoo := 10

TestSetOwp()

U_Foo() não tem  acesso a variável Publica declarada Explicitamente em uma rotina de nível inferior.

Type("nPrvtNoSetOwp")  -> "U"

Aqui U_Foo() tem acesso à variável nPrvtSetOwp declarada pela _SetOwnerPrvt()

Type("nPrvtSetOwp")  -> "N"

Return( NIL )

Static Function TestSetOwp()

Neste Ponto TestSetOwp() tem acesso à variável Private declarada um nível acima
Type("nPrvtFoo")  -> "N" 

Declarando dessa forma todas as rotinas a partir deste ponto terão acesso e a rotina chamadora também terá acesso à esse variável

_SetOwnerPrvt( "nPrvtNoSetOwp" , 1512 )

Type("nPrvtNoSetOwp") -> "N" 

Declarando dessa forma apenas as rotinas chamadas à partir desse ponto terão acesso

Private nPrvtNoSetOwp := 1215

Type("nPrvtNoSetOwp")  -> "U" 

Return( NIL )

O Problema dessas variáveis é que elas só estão disponíveis dentro da Thread que as criou, se necessitarmos ter acesso ao conteúdo dessar variáveis em outra Thread não será possível. É aí que entra a variável se escopo Global. Para manipularmos as variáveis de escopo Global teremos que usar as seguintes funções da API:

Para executar o Lock nas Global

GlbLock() 

Para Declarar uma Variável e/ou Atribuir um novo valor

PutGlbValue(  cVar  , cValue ) 

Para liberar o Lock nas Global

GlbUnlock() 

Para obter os valores das Global.

GetGlbValue( cVar )   

Um pequeno fragmanto do código u_sudoku.prg modificado para exemplificar o uso da variável de escopo Global

Tento obter a exclusividade na pilha variáveis de escopo Global

While !( GlbLock() )
Sleep(5)
End While

Se a variavel bStartSudoku não estiver declarada, declaro-a, setanto seu valor Inicial

PutGlbValue( "bStartSudoku" , "1" )

Se a variavel cSudokuTime não estiver declarada, declaro-a, setanto seu valor Inicial

PutGlbValue( "cSudokuTime" , "00:00:00" )

Libero o Lock na pilha de variáveis de escopo Global

GlbUnlock()

Executo StartJob para a criação de uma nova Thread

StartJob( "U_SudokuExec" , GetEnvServer() , .F. , "SudokuTime" , { Time() , 1 } )

Tanto bStartSudoku quanto cSudokuTime poderão ser lidas através de GetGlbValue(cVar)   e modificadas, utilizando  PutGlbValue(cVar,cVal), por qualquer Thread criada à partir de sua declaração e terão validade até que a última Thread seja liberada.

Comentários

  1. Saudações Naldo,

    Sobre variaveis de escopo STATIC, tenho um arquivo fisico que contem abaixo dos INCLUDES variaveis estaticas declaradas, por exemplo:

    #include 'Protheus.ch'

    STATIC xBarrType := Iif(IsSrvUnix(),'/','\')

    .
    .
    .
    Varias U_Functions => (UFn)
    .
    .
    .
    Minha duvida é, se ao chamar uma UFn nesse fonte
    a variavel STATIC sera iniciada também?

    Abs,
    Sergio

    ResponderExcluir
  2. Cara a função _SetOwnerPrvt() é a maior sacada com certeza... eu sempre me ferrava nos pontos de entrada... com ela acabou as gambiarras !!! vlww

    ResponderExcluir
  3. Pessoal, boa noite.

    Eu estou usando esse conceito para resolver um problema aqui, mas travei na seguinte situação:

    Consigo carregar uma tabela em uma Thread e ler em outra ? Ou seja:

    Na função A, inicio a função B como JOB. Nessa função B, eu carrego uma tabela com o TcGenQry, no alias "view1".
    Gostaria de ler os campos dessa "view1" na função A.

    É possivel?

    ResponderExcluir
    Respostas
    1. Não. Não é possível por causa da forma que threads foram implementadas no sistema. Exceto pelas variáveis do tipo Global, nenhuma outra é compartilhada entre threads. Mas a solução do seu problema é simples: crie uma tabela temporária a partir da sua view e ela poderá ser acessada por qualquer thread.

      Excluir
  4. Vlw Naldo. Brigado mesmo.

    Agora só mais uma forcinha. Sabe qual melhor forma de fazer isso, pensando na performance? Essa rotina em questão eh um relatório, que já leva horas para carregar a view, e a ideia seria não dobrar esse tempo ao jogar em uma tabela temporaria...

    ResponderExcluir
    Respostas
    1. Já tentou extrair os dados (criando uma tabela) via Procedure???

      Excluir
  5. Consegui um resultado muito bacana com as temporárias globais do sql mesmo. Assim que terminar posto o resultado completo aqui.

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

BlackTDN :: RLeg ~ Desvendando a Função ParamBox

Para quem precisar desenvolver uma interface de entrada de dados, coisa rápida, e não quer ter aquele trabalhão danado que todos já sabemos, o Protheus tem uma função que ajuda muito, é uma interface semelhante a função Pergunte, porém com muito mais opção de objeto de entrada de dados, alias até colocar o scrollbox desta interface com todos os objetos em outra MsDialog ou Wizard é simples. Vejam o exemplo abaixo, boa sorte! Rleg. //---------------------------------------------------------- // Função exemplo utilizando a função ParamBox() //---------------------------------------------------------- User Function xParamBox() Local aRet := {} Local aParamBox := {} Local aCombo := {"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"} Local i := 0 Private cCadastro := "xParambox" // ---------------

BlackTDN :: Customizando a interface de Login no Protheus e by You

A publicação “ BlackTDN :: By You e sua nova tela de login ”  de nosso amigo OBona deu o que falar e, em função disso, esse que a muito não vos escreve resolveu criar uma versão onde será possível personalizar, “por completo”, a tela de login no Protheus/by You. Considerando que OBona já havia “mapeado, identificado e customizado” as imagens peguei-as emprestadas para o exemplo que se segue: O primeiro passo para a customização “total” da interface de login do Protheus/by You será implementar o “Ponto de Entrada” ChgPrDir (Diretório de impressão) . Usaremos esse PE juntamente como programa U_FindMsObject.prg (apresentado pela primeira vez em: Protheus :: ADVPL : The Container : Presents Pandora's box ). Diferente do exemplo proposto por OBona, que substitui, durante o processo de compilação, as imagens padrões do sistema (excluindo-as) por imagens customizadas (com o mesmo nome) este novo exemplo mantém, no RPO, as imagens padrões adicionando novas imagens customizadas que serã

Protheus :: Chamando Funções do Menu Diretamente e sem a Necessidade de Login

Ferne$ perguntou: "...é possível abrir alguma rotina do sistema sem solicitar login ao usuário, como por exemplo a rotina MATA010..." Sim Ferne$, é possível sim. Abaixo um Exemplo para a Chamada à função MATA010 sem a necessidade de Login no sistema. #INCLUDE "PROTHEUS.CH" #INCLUDE "TBICONN.CH" /*/ Funcao: MATA010Ex Data: 30/04/2011 Autor: Marinaldo de Jesus Descricao: Executar a Funcao MATA010 diretamente sem a necessidade de LOGIN no Protheus Sintaxe: 1 ) U_MATA010Ex ( Chamada diretamente na Tela de Entrada do Sistema ) ; ou 2 ) totvsclient.exe -q -p=u_MATA010Ex -a=01;01 -c=rnp_local -e=rnp -m -l ( Chamada Via Linha de Comando ) /*/ User Function MATA010Ex( cEmpFil ) Local aEmpFil Local bWindowInit := { || __Execute( "MATA010()" , "xxxxxxxxxxxxxxxxxxxx" , "MATA010" , "SIGAFAT" , "SIGAFAT", 1 , .T. ) } Local cEmp Local cFil Local cMod Local cModName := "SIGAFAT" DEFA