{"id":448,"date":"2016-08-30T00:23:51","date_gmt":"2016-08-30T03:23:51","guid":{"rendered":"http:\/\/www.pascalscada.com\/?page_id=448"},"modified":"2026-09-17T09:36:53","modified_gmt":"2026-09-17T12:36:53","slug":"tmutexserver-and-tmutexclient","status":"publish","type":"page","link":"https:\/\/www.pascalscada.com\/pb\/tmutexserver-and-tmutexclient\/","title":{"rendered":"TMutexServer e TMutexClient"},"content":{"rendered":"<h5>Introdu\u00e7\u00e3o<\/h5>\n<p>Em primeiro lugar, sinta-se livre para enviar corre\u00e7\u00f5es de qualquer tipo, incluindo reformula\u00e7\u00f5es de texto.<\/p>\n<p>Este artigo tem como objetivo principal, ensinar a usar e a entender os cen\u00e1rios onde as classes TMutexServer e TMutexClient devem ser usadas. Um resumo das propriedades de cada um ser\u00e1 abordado a seguir.<\/p>\n<h5>O que s\u00e3o as classes TMutexServer e TMutexClient<\/h5>\n<p>As classes TMutexServer e TMutexClient s\u00e3o em resumo um <a href=\"https:\/\/pt.wikipedia.org\/wiki\/Regi%C3%A3o_cr%C3%ADtica\">mutex, regi\u00e3o\/se\u00e7\u00e3o cr\u00edtica<\/a>, usados para fazer a prote\u00e7\u00e3o de recursos exclusivos e o sincronismo de processos. Por\u00e9m o detalhe que mais chama aten\u00e7\u00e3o nas classes TMutexServer e TMutexClient \u00e9 que eles s\u00e3o feitos para funcionar em rede, ou seja, s\u00e3o feitos para sincronizar processos que est\u00e3o rodando em diferentes computadores. Neste cen\u00e1rio, precisamos de um servidor, arbitrando quem tem a vez sobre o recurso, e dois ou mais sistemas rodando em computadores diferentes (ou duas ou mais inst\u00e2ncias da mesma aplica\u00e7\u00e3o rodando em uma ou mais esta\u00e7\u00f5es) que concorrem a um recurso comum. A imagem abaixo ilustra esta situa\u00e7\u00e3o:<\/p>\n<p>(imagem)<\/p>\n<p>Algo muito importante a se notar nestes componentes \u00e9 que eles s\u00e3o feitos para serem chamados exclusivamente via c\u00f3digo. Portanto, n\u00e3o h\u00e1 maneiras gr\u00e1ficas (ou f\u00e1ceis) de proteger seus recursos que necessitam acesso exclusivo.<\/p>\n<p>Por fim, para dar acesso exclusivo a um recurso ou fazer o sincronismo entre v\u00e1rios processos que est\u00e3o rodando diferentes esta\u00e7\u00f5es, \u00e9 necess\u00e1rio fazer o uso da classe TMutexClient em cada uma das aplica\u00e7\u00f5es que concorrentes. Portanto, se uma aplica\u00e7\u00e3o n\u00e3o fizer o uso desta classe, comportamento inesperados podem acontecer.<\/p>\n<h5>Quando devo usar as classes TMutexServer e TMutexClient<\/h5>\n<p>\u00c9 recomendado usar as classes TMutexServer e TMutexClient nas seguintes situa\u00e7\u00f5es:<\/p>\n<ul>\n<li>Quando a integridade de v\u00e1rias escritas devem ser garantidas, evitando que uma aplica\u00e7\u00e3o sobrescreva os dados enviados por outra.<\/li>\n<li>Quando se deseja acesso exclusivo a um recurso (CLP) quando determinadas a\u00e7\u00f5es estejam sendo executadas em um ambiente com m\u00faltiplas aplica\u00e7\u00f5es.<\/li>\n<\/ul>\n<h5>Onde encontro as classes TMutexServer e TMutexClient<\/h5>\n<p>Ambas as classes s\u00e3o disponibilizadas quando \u00e9 instalado o pacote pascalscada.lpk.<\/p>\n<p>Uma vez instalado este pacote, dois itens na paleta \u201cPascalSCADA utils\u201d ser\u00e3o exibidos, conforme a figura abaixo:<\/p>\n<p><a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Captura-de-tela-de-2016-11-29-191818.png\"><img decoding=\"async\" alt=\"Captura de tela de 2016-11-29 19:18:18\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Captura-de-tela-de-2016-11-29-191818.png\"><\/a><\/p>\n<h5>Como configurar uma aplica\u00e7\u00e3o para usar as classes TMutexServer e TMutexClient<\/h5>\n<p>Esta configura\u00e7\u00e3o \u00e9 feita em duas etapas, uma do lado servidor e outra no lado da(s) aplica\u00e7\u00e3o(\u00f5es) cliente(s)<\/p>\n<h6>No servidor:<\/h6>\n<p>Na aplica\u00e7\u00e3o ou servi\u00e7o que ir\u00e1 arbitrar o sincronismo\/acesso ao recurso s\u00e3o necess\u00e1rias alguns poucos passos:<\/p>\n<ol>\n<li>Insira no seu projeto uma instancia da classe TMutexServer para cada recurso com acesso exclusivo que deseja proteger;<\/li>\n<li>Configure a porta TCP\/IP que este servidor de mutex ir\u00e1 atender as requisi\u00e7\u00f5es clientes. Este n\u00famero n\u00e3o pode repetir caso v\u00e1rias inst\u00e2ncias da classe TMutexServer estejam inseridas e habilitadas na sua aplica\u00e7\u00e3o\/servi\u00e7o. A porta informada tamb\u00e9m deve estar dispon\u00edvel, pois a classe TMutexServer ir\u00e1 abri-l\u00e1 para aceitar conex\u00f5es. Portanto, modifica\u00e7\u00f5es no seu firewall podem ser necess\u00e1rias.<br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_447.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_447\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_447.png\"><br \/>\n<\/a><\/li>\n<li>Ative o Mutex server, alterando a propriedade Active para true:<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_448.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_448\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_448.png\"><\/a><\/li>\n<li>Rode sua aplica\u00e7\u00e3o\/servi\u00e7o. Se estiver fazendo isto em um sistema operacional Windows, a primeira vez que rodar seu servi\u00e7o, uma pergunta do firewall querendo saber se voc\u00ea autoriza a abertura da porta ser\u00e1 exibida. Em sistemas derivados do Unix (e no Windows tamb\u00e9m), basta usar o utilit\u00e1rio <em>netstat<\/em> para verificar quais portas est\u00e3o abertas:<br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_449.png\"><br \/>\n<\/a><a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_449.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_449\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_449.png\"><\/a><\/li>\n<\/ol>\n<h6>Nas aplica\u00e7\u00f5es clientes<\/h6>\n<p>A configura\u00e7\u00e3o das aplica\u00e7\u00f5es clientes se resumem a duas etapas b\u00e1sicas, sendo elas a configura\u00e7\u00e3o da conex\u00e3o com o servidor mutex e ap\u00f3s isso, a altera\u00e7\u00e3o do c\u00f3digo para verifica\u00e7\u00e3o de acesso exclusivo ao recurso.<\/p>\n<p>A configura\u00e7\u00e3o da conex\u00e3o do mutex client \u00e9 muito semelhante a configura\u00e7\u00e3o do mutex server, sendo necess\u00e1rio configurar duas propriedades extras: a primeira \u00e9 o endere\u00e7o IPv4 do mutex server. <strong>Aten\u00e7\u00e3o: somente endere\u00e7os IPv4 s\u00e3o aceitos! N\u00e3o tente inserir endere\u00e7os IPv6 ou nome de hosts!<\/strong> A segunda configura\u00e7\u00e3o que precisa ser feita \u00e9 dizer qual \u00e9 o comportamento do Mutex Client caso este esteja tendo dificuldades em conectar no mutex server, sendo a configura\u00e7\u00e3o de negar acesso o seu padr\u00e3o. Acompanhe as imagens que seguem:<\/p>\n<ol>\n<li>Insira na sua aplica\u00e7\u00e3o uma inst\u00e2ncia da classe TMutexClient. Neste exemplo, ser\u00e3o inseridas duas inst\u00e2ncias da classe para que seja poss\u00edvel reproduzir uma situa\u00e7\u00e3o de concorr\u00eancia.<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_451.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_451\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_451.png\"><\/a><\/li>\n<li>Configure o endere\u00e7o dos mutex clients para que estes encontrem o mutex server, que \u00e9 quem ir\u00e1 arbitrar quem ter\u00e1 acesso ao recurso exclusivo. <strong>Lembre-se: somente IPv4 \u00e9 aceito!<\/strong><br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_452.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_452\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_452.png\"><\/a><\/li>\n<li>Informe a porta do mutex server para os clientes. No nosso exemplo mantivemos o padr\u00e3o.<br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_453.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_453\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_453.png\"><\/a><\/li>\n<li>Configure a propriedade <em>DefaultBehavior<\/em> , pois \u00e9 ela quem configura o comportamento padr\u00e3o quando o mutex client n\u00e3o consegue conex\u00e3o com o mutex server. Esta configura\u00e7\u00e3o estando com o valor <em>False<\/em> , ir\u00e1 negar acesso ao recurso caso o mutex client esteja desconectado.Caso o esta propriedade seja <em>True e<\/em> o cliente esteja desconectado do mutex server, uma tentativa de acesso feita nesse momento resultar\u00e1 na libera\u00e7\u00e3o de acesso ao recurso. <strong>Use com cuidado!<\/strong><\/li>\n<li>Por \u00faltimo, basta ativar a conex\u00e3o para que os clientes conectem no mutex server configurado.<br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_454.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_454\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_454.png\"><br \/>\n<\/a><\/li>\n<li>Rode a aplica\u00e7\u00e3o e verifique se as conex\u00f5es com o mutex server foram estabelecidas usando o netstat.<br \/>\n<a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_456.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_456\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_456.png\"><\/a><\/li>\n<\/ol>\n<p>Irei neste exemplo, adicionar dois panels quer ir\u00e3o funcionar como bot\u00f5es (sim Panels, pelo simples fato que as classes de bot\u00f5es nativas n\u00e3o aceitam o valor da propriedade color), que no primeiro clique ir\u00e3o solicitar o recurso ao mutex server e no clique seguinte ir\u00e1 liberar acesso. Caso o bot\u00e3o clicado obtenha o recurso, ele ir\u00e1 trocar a cor do bot\u00e3o. <a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_459.png\"><img decoding=\"async\" alt=\"Sele\u00e7\u00e3o_459\" src=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_459.png\"><\/a><a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_457.png\"><br \/>\n<\/a><a href=\"http:\/\/www.pascalscada.com\/wp-content\/uploads\/2016\/08\/Sele\u00e7\u00e3o_455.png\"><br \/>\n<\/a><\/p>\n<p>D\u00ea dois cliques no primeiro bot\u00e3o e insira o seguinte c\u00f3digo no evento OnClick:<\/p>\n<pre class=\"brush: delphi; tab-size: 2; title: ; notranslate\" title=\"\">procedure TForm1.Button1Click(Sender: TObject);\nbegin\n  if Button1.Color = clLime then begin\n    if MutexClient1.Leave then\n      Button1.Color := clDefault;\n  end else begin\n    if MutexClient1.TryEnter then begin\n      Button1.Color := clLime;\n    end;\n  end;\nend;<\/pre>\n<p>Repita o procedimento e insira este c\u00f3digo no evento OnClick do objeto Button2:<\/p>\n<pre class=\"brush: delphi; tab-size: 2; title: ; notranslate\" title=\"\">procedure TForm1.Button2Click(Sender: TObject);\nbegin\n  if Button2.Color = clLime then begin\n    if MutexClient2.Leave then\n      Button2.Color := clDefault;\n  end else begin\n    if MutexClient2.TryEnter then begin\n      Button2.Color := clLime;\n    end;\n  end;\nend;<\/pre>\n<p>O video de funcionamento deste exemplo pode ser visto aqui:<\/p>\n<figure class=\"wp-block-embed wp-block-embed-youtube is-type-video is-provider-youtube epyt-figure\"><div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\"  id=\"_ytid_54502\"  width=\"800\" height=\"600\"  data-origwidth=\"800\" data-origheight=\"600\" src=\"https:\/\/www.youtube.com\/embed\/5XoYhBTjJ1c?enablejsapi=1&autoplay=0&cc_load_policy=0&cc_lang_pref=&iv_load_policy=1&loop=0&rel=1&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=1&disablekb=0&\" class=\"__youtube_prefs__  no-lazyload\" title=\"YouTube player\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><\/div><\/figure>\n<p>Como visto no acima, a class TMutexClient tem duas primitivas b\u00e1sicas que solicitam e liberam o recurso, que s\u00e3o identicas ao da classe TCriticalSection:<\/p>\n<ul>\n<li><strong>TryEnter<\/strong> : Fun\u00e7\u00e3o que retorna um valor booleano <em>true<\/em> caso o acesso ao recurso foi autorizado (pelo mutex server ou pela propriedade <em>DefaultBehavior<\/em>) ou <em>false<\/em> caso contr\u00e1rio. Esta fun\u00e7\u00e3o n\u00e3o retorna a fonte do valor (mutex server ou propriedade <em>DefaultBehavior<\/em>).<\/li>\n<li><strong>TryEnter(out PickedTheDefaultBehavior: Boolean)<\/strong> : Fun\u00e7\u00e3o que retorna um valor booleano <em>true<\/em> caso o acesso ao recurso foi autorizado (pelo mutex server ou pela propriedade <em>DefaultBehavior<\/em>) ou <em>false<\/em> caso contr\u00e1rio. Esta fun\u00e7\u00e3o retorna outro valor booleano <em>true<\/em> caso o resultado da fun\u00e7\u00e3o tenha sido obtido da propriedade <em>DefaultBehavior<\/em>. Ou seja, caso o valor da vari\u00e1vel passada para o par\u00e2metro <strong>PickedTheDefaultBehavior<\/strong> retorne com <strong>true<\/strong> , <strong>voc\u00ea est\u00e1 desconectado do mutex server!<\/strong><\/li>\n<li><strong>Leave<\/strong> : fun\u00e7\u00e3o que libera o recurso, caso o respectivo mutex client tenha acesso sobre ele. Retorna true toda a vez que o mutex client tem o recurso e faz a libera\u00e7\u00e3o do mesmo e false caso o contr\u00e1rio.<\/li>\n<\/ul>\n<h5>Problemas de conex\u00e3o, deadlocks, e libera\u00e7\u00e3o autom\u00e1tica do mutex server<\/h5>\n<p>O mutex server est\u00e1 programado para liberar o mutex interno, caso ap\u00f3s alguns segundos, o mutex client n\u00e3o responder aos comandos de ping. As requisi\u00e7\u00f5es de ping s\u00e3o enviadas a cada um segundo. Ap\u00f3s o envio o mutex server aguarda durante um segundo a resposta do mutex client. Caso ocorra uma falha no mutex server enviando ou recebendo o ping, um contador de falhas \u00e9 incrementado. Quando este contador atinge um valor maior ou igual a dez, \u00e9 iniciado o procedimento de desligamento deste mutex client com problemas e caso ele tenha a posse do mutex, faz a devida libera\u00e7\u00e3o do mesmo.<\/p>\n<p>No lado cliente, uma conex\u00e3o perdida \u00e9 recuperada toda a vez que uma chamada as fun\u00e7\u00f5es TryEnter s\u00e3o feitas.<\/p>\n<p>Deadlocks no mutex server s\u00f3 n\u00e3o podem ser evitados caso o cliente n\u00e3o fa\u00e7a a devida libera\u00e7\u00e3o do mutex (nunca chame a fun\u00e7\u00e3o Leave), seja por erro na l\u00f3gica ou congelamento da aplica\u00e7\u00e3o.<\/p>\n<p>Tanto o mutex server quanto o mutex client iniciam threads para poder enviar e responder os comandos de ping sem sofrer ou causar interfer\u00eancia no loop principal da aplica\u00e7\u00e3o.<\/p>\n<h5>Aplica\u00e7\u00e3o exemplo<\/h5>\n<p>Este exemplo est\u00e1 dispon\u00edvel em:<br \/>\n<a href=\"https:\/\/sourceforge.net\/p\/pascalscada\/code\/HEAD\/tree\/trunk\/examples\/laz_networkmutex\/\">https:\/\/sourceforge.net\/p\/pascalscada\/code\/HEAD\/tree\/trunk\/examples\/laz_networkmutex\/<\/a><\/p>\n<p>H\u00e1 tamb\u00e9m um outro exemplo, mais din\u00e2mico:<br \/>\n<a href=\"https:\/\/sourceforge.net\/p\/pascalscada\/code\/HEAD\/tree\/trunk\/examples\/both_networkmutex\/\">https:\/\/sourceforge.net\/p\/pascalscada\/code\/HEAD\/tree\/trunk\/examples\/both_networkmutex\/<\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>Introdu\u00e7\u00e3o Em primeiro lugar, sinta-se livre para enviar corre\u00e7\u00f5es de qualquer tipo, incluindo reformula\u00e7\u00f5es de texto. Este artigo tem como objetivo principal, ensinar a usar e a entender os cen\u00e1rios &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"page-templates\/full-width.php","meta":{"footnotes":""},"class_list":["post-448","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/448","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/comments?post=448"}],"version-history":[{"count":38,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/448\/revisions"}],"predecessor-version":[{"id":1239,"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/pages\/448\/revisions\/1239"}],"wp:attachment":[{"href":"https:\/\/www.pascalscada.com\/pb\/wp-json\/wp\/v2\/media?parent=448"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}