Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++Builder Discussion :

Problème de synchronisation


Sujet :

C++Builder

  1. #1
    Membre éprouvé
    Problème de synchronisation
    Bonjour

    J'ai fait un serveur TCP avec le composant TidTCPServer dans une application FMX. Dans la méthode ServeurExecute je lit les données reçues et j'en affiche une partie dans une liste box.

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    void __fastcall TForm1::ServeurExecute(TIdContext *AContext) {
    	TByteDynArray pInfo;
    	unsigned short data[32 * 25];
    	char chaine[256];
    	try {
    		AContext->Connection->IOHandler->ReadBytes(pInfo, 1856, false);
    		memcpy(chaine, &pInfo[0], 256);
    		memcpy(data, &pInfo[256], 32*25*2);
    		String rep = "";
    		int n = 0;
    		while (n < 256 && chaine[n] != 0) {
    			rep += chaine[n];
    			n++;
    		};
    		updateListe(rep);//rafraichissement de la liste
     
    	}
    	catch (const Exception& e) {
    		// AFAIRE
    	}
    }


    Manifestement la fonction d'affichage ci dessous ne supporte pas d'être accédé par un thread. Car j'ai régulièrement des exceptions qui normalement n'ont pas lieu d'être

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void __fastcall TForm1::updateListe(String rep) {
    	lbReseau->Items->Add(rep);
    	if (lbReseau->Items->Count > 10)
    		lbReseau->Items->Delete(0);
    }


    Pour éviter cela, j'ai vu qu'il fallait que j'utilise la méthode Synchronize mais je n'arrive pas à la mettre en oeuvre.

    En effet j'ai voulu utiliser TIdThread.Synchronize mais il ne veux pas compiler cette ligne.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    TIdThread::Synchronize((TThreadMethod)&updateListe(rep));

    Voici l'erreur E2109 Ce n'est pas un type autorisé

    Une idée?
    Il y a des jours où j'éprouve une haine profonde envers microsoft
    Venez vous défouler ici ou c'est amusant
    Mon modeste site et mes modestes oeuvres sont
    Rémi

  2. #2
    Membre chevronné
    Salut
    ta manière d'utiliser ce composant me semble incorrecte
    je te conseille de regarder le lien suivant:http://codeverge.com/embarcadero.cppbuilder.socket/basic-functionality-tidtcpserve/1080046
    ou en delphi un code plus complet https://silverpeacock.wordpress.com/2017/07/30/delphi-client-server-indy-embarcadero-tcp-tiditcpserver-tidtcpclient-components/
    bien cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  3. #3
    Membre éprouvé
    Merci pour ces exemples.
    Malheureusement ils ne fonctionnent pas avec FMX.
    L'include #include <IdAntiFreeze.hpp> bloque la compilation avec cette erreur [ilink32 Erreur] Fatal: Impossible d'ouvrir le fichier 'VCL.FORMS.OBJ'
    Sinon j'ai trouvé cette solution:
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
     
    //appel de la fonction de mise à jour de la liste des messages
     TThread::Synchronize(NULL, (TThreadMethod)&updateListe);


    fonction de mise à jour des messages
    TClientTCP est un objet créé à la connexion et contient les informations à traiter qui on été reçue dans la fonction ServeurExecute.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    void __fastcall TScarboMainForm::updateListe() {
    	TClientTCP *clx = NULL;
    	String rep;
     
    	for (int n = 0; n < pClients->Count; n++) {
    		clx = (TClientTCP*)pClients->Items[n];
    		rep = clx->getInfo();
    		if (!rep.IsEmpty()) {
    			lbReseau->Items->Add(rep);
    			if (lbReseau->Items->Count > 10)
    				lbReseau->Items->Delete(0);
    		}
    	}
    }


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void __fastcall TScarboMainForm::ServeurConnect(TIdContext *AContext) {
    	TClientTCP *cl = new TClientTCP(0, AContext);
    	pClients->Add(cl);
    }


    La fonction ServeurExecute
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     
    void __fastcall TScarboMainForm::ServeurExecute(TIdContext *AContext) {
    	TByteDynArray pInfo;
    	bool trouve = false;
    	int nctx = 0;
    	char chaine[256];
    	TClientTCP *clx = NULL;
    	try {
     
    		while (!trouve && nctx < pClients->Count) {
    			clx = (TClientScarbo*)pClients->Items[nctx];
    			trouve = (clx->getContext() == AContext);
    			nctx++;
    		}
    		if (trouve) {
    			if (clx->getID() == 1 || clx->getID() == 2)
    				AContext->Connection->IOHandler->ReadBytes(pInfo, 17440, false);
    			if (clx->getID() == 3)
    				AContext->Connection->IOHandler->ReadBytes(pInfo, 786688, false);
    			if (clx->getID() == 0)
    				AContext->Connection->IOHandler->ReadBytes(pInfo, 256, false);
     
    			memcpy(chaine, &pInfo[0], 256);
    			String lrep = "";
    			int n = 0;
    			while (n < 256 && chaine[n] != 0) {
    				lrep += chaine[n];
    				n++;
    			}
    			int deb = lrep.Pos("IDENTIFIANT");
    			if (deb > 0) {
    				String num = lrep.SubString(deb + 8, 1);
    				int ref = num.ToInt();
    				if (ref == 1 || ref == 2)
    					clx->setDataBuff(64*64*4);
    				if (ref == 3)
    					clx->setDataBuff(512*512*4);
    				clx->setID(ref);
    				clx->setON(true);
    				TThread::Synchronize(NULL, (TThreadMethod)&updateLed);
    			}
    			else {
    				void *data = clx->getDataBuff();
    				clx->setInfo(lrep);
    				memcpy(data, &pInfo[256], clx->getTailleData());
    				TThread::Synchronize(NULL, (TThreadMethod)&updateListe);
    				TThread::Synchronize(NULL, (TThreadMethod)&updateImg);
    			}
     
    		}
    	}
    	catch (const Exception& e) {
    		// AFAIRE
    	}
    }
    Il y a des jours où j'éprouve une haine profonde envers microsoft
    Venez vous défouler ici ou c'est amusant
    Mon modeste site et mes modestes oeuvres sont
    Rémi

  4. #4
    Membre chevronné
    Salut
    Merci pour le code fournit
    en fait l'include #include <IdAntiFreeze.hpp> n''est pas nécessaire dans ce cas
    il y aura peut-être d'autres erreurs

    par ailleurs l'utilisation de synchronize est déconseillé car cette méthode est symchrone et peut bloqué le thread, il est préférable d'utiliser la méthode Queue qui est asynchrone ou un bon vieux PostMessage qui utilise la boucle de Message Windows

    bien cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  5. #5
    Membre chevronné
    Salut,
    pour revenir à mon précédent post concernant l'utilisation de TThread::Queue
    j'ai un peu investigué et voici une solution que je trouve élégante
    pour travailler avec les méthodes Anonymes de Delphi avec C++ Builder il faut mettre en place tout une usine à Gaz en utilisant la classe TCppInterfacedObject

    exemple j'ai besoin envoyer sur le thread principal le nombre de clients connectés, ainsi que les Traces récoltées
    voici le code à utiliser

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
     
    class TNotifier : public TCppInterfacedObject<TThreadProcedure> {
    	int lValue;
    private:
    	TFMicroServer* form;
    public:
    	TNotifier(int ValSet, TFMicroServer* _form) : lValue(ValSet), form(_form) {}
    	INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
    	void __fastcall Invoke() {form->clients_connected->Text = lValue;}
    } ;
    // ---------------------------------------------------------------------------
     
    class TLogMessage : public TCppInterfacedObject<Classes::TThreadProcedure> {
    	String Msg;
    private:
    	TFMicroServer* form;
    public:
    	TLogMessage(String _Msg, TFMicroServer* _form) : Msg(_Msg), form(_form) {}
    	INTFOBJECT_IMPL_IUNKNOWN(TInterfacedObject);
     
    	void __fastcall Invoke() {form->messagesLog->Lines->Add(Msg);}
    } ;
     
    // ---------------------------------------------------------------------------
     
    //Ces méthodes seront utilisées de la manière suivante
     
    TThread::Queue(NULL, Classes::_di_TThreadProcedure(new TNotifier(nClients,
    	 this)));
    // notification du nombre de clients
     
    	UnicodeString Tmp("[" + p_sender + "]" + GetNow() + ":" + p_message);
    	TThread::Queue(NULL, Classes::_di_TThreadProcedure(new TLogMessage(Tmp,
    	  this)));
    }


    je suis à disposition en cas de renseignements complémentaires
    je joins un code complet fonctionnel en FMX

    bien cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  6. #6
    Membre éprouvé
    Merci pour le code je vais regarder ce que ça donne chez moi
    Il y a des jours où j'éprouve une haine profonde envers microsoft
    Venez vous défouler ici ou c'est amusant
    Mon modeste site et mes modestes oeuvres sont
    Rémi

  7. #7
    Membre chevronné
    Salut,
    Peux-tu me faire part de ton expérience avec les Threads Queues.
    J’ai pour ma part modifier avec succès pas mal de mes grammes fonctionnant auparavant avec la méthode synchronize
    Cdlt
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  8. #8
    Membre éprouvé
    Désolé pour la réponse tardive mais j'ai du basculer sur un autre sujet. J'ai fait la modification sur mon programme et je dirais qu'après les premiers tests je ne constate pas de grosse différence au niveau des performances.
    Par contre ta méthode est plus intéressante dans la mesure ou il est possible de passer des paramètres ce qui n'est pas le cas avec Synchronize.
    Conclusion j'utilise ta méthode maintenant.
    Il y a des jours où j'éprouve une haine profonde envers microsoft
    Venez vous défouler ici ou c'est amusant
    Mon modeste site et mes modestes oeuvres sont
    Rémi

  9. #9
    Membre chevronné
    merci pour ton retour
    la différence fondamentale entre synchronize et les queues réside dans le fait que les queues utilisent un mode asynchrone, quelque peu identique à l'emploi de PostMessage.
    j'ai modifié beaucoup de mes applications qui utilisait synchronize au profit des queues qui quoique un peu plus difficile à mettre en œuvre sont plus efficientes

    bien cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

  10. #10
    Membre actif
    Effectivement je n'avais jamais pensé à ça. Perso je le fais tout le temps avec mes grosses pattounes en claquant un gros :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    TThread::Synchronize(TThread::CurrentThread,BMP2JPG);


    en plein milieu du ServeurExecute

    Ouai c'est moche mais ça marche bien de mon coté, je n'ai jamais eut de souci avec en tout cas.


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    void __fastcall TForm1::IdTCPServer1Execute(TIdContext *AContext)
    {
    	unsigned char Commande = AContext->Connection->Socket->ReadByte();
    	// commande "Envoyer une photo"
     
    	if (Commande == 0x02)
    	{
    		TThread::Synchronize(TThread::CurrentThread,BMP2JPG);
    		jpg->CompressionQuality=50;
    		jpg->SaveToStream(RAM);
    		RAM->Seek(0,0);
    		AContext->Connection->Socket->Write( (unsigned int) RAM->Size);
    //		this->Memo1->Lines->Add(RAM->Size);
    		AContext->Connection->Socket->Write(RAM);
    		RAM->Clear();
    	}
    	else if (Commande == 0x03) // commande "envoyer une vidéo de 25 images"
    	{
    		for (int i = 0; i < 25; i++)
    		{
    			Sleep(1000/25);
    			TThread::Synchronize(TThread::CurrentThread,BMP2JPG);
    			jpg->CompressionQuality=1;
    			jpg->SaveToStream(RAM);
    			RAM->Seek(0,0);
    			AContext->Connection->Socket->Write( (unsigned int) RAM->Size);
    //			this->Memo1->Lines->Add(RAM->Size);
    			AContext->Connection->Socket->Write(RAM);
     
    			RAM->Clear();
    		}
    	}
     
    }
    Désolé, on savait pas que c'était impossible, alors on l'a fait

  11. #11
    Membre chevronné
    Salut,
    Sans vouloir faire une pub exagéré pour l'utilisation de TThread::Queue:
    cependant...:
    ca simplifie considérablement la tâche:
    j'ai réalisé un traitement centralisé des Traces émises par mes différents forms. ainsi que le traitement des messages d'erreurs retournées
    Avantage:
    Affichage dans un seul composant, (TMemo) de ma form principale et non pas dans chaque fiche de tous les messages d'erreurs de mon application,
    je fais de même pour la gestion centralisée des Traces (Log)
    Toutes les fiches que tu utilise dans une application sont composées également d'un ou plusieurs Threads ce qui rend très intéressant l'emploi de TThread::Queue

    cordialement
    vous trouverez mes tutoriels à l'adresse suivante: http://djmsoftware.developpez.com/
    je vous en souhaite une excellente lecture ...

    A lire : Les règles du forum

###raw>template_hook.ano_emploi###