IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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

Threads & Processus C++ Discussion :

[THREAD][AFX]Passage de parametre


Sujet :

Threads & Processus C++

  1. #1
    Membre à l'essai
    Inscrit en
    Juillet 2007
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 11
    Points : 11
    Points
    11
    Par défaut [THREAD][AFX]Passage de parametre
    Bonjour,

    lors du développement d'une solution, j'aurais besoin de passer une classe contenant mes paramètres (via pointeur) a mon thread secondaire actuellement voici ce que je fait (je poste juste une partie du code si besoin je mettrai le fichier complet)

    deploy.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    myParam.SetParam(m_pSettings, m_pComputerList, &m_FailedList);
    		m_pThreadLauncher = AfxBeginThread((AFX_THREADPROC)InstallComputerList, &myParam, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
    		m_pThreadLauncher->m_bAutoDelete = FALSE;
    		m_pThreadLauncher->ResumeThread();
    Pour vous indiquez a quoi coresponde les variable voici le

    deploy.h
    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
     
     
    class CDeployingDlg : public CDialog
    {
    // Construction
    public:
    	CDeployingDlg(CWnd* pParent = NULL);   // standard constructor
     
    	// Set agent settings to use for deploying, either Windows or Unix settings
    	void SetAgentSetting( CAgentSettings *pSettings);
    	// Set list of computer to setup
    	void SetComputerList( CStringList *pList);
     
    // Dialog Data
    	//{{AFX_DATA(CDeployingDlg)
    	enum { IDD = IDD_DEPLOYING_DIALOG };
    	CSliderCtrl	m_SliderThreads;
    	CListBox	m_ListBox;
    	//}}AFX_DATA
    void StartUp();
     
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CDeployingDlg)
    	protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
     
    	virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    	//}}AFX_VIRTUAL
     
    // Implementation
    protected:
    	// Message Handler allowing thread to update status and listbox content
    	LRESULT OnMessageHandlerListbox( LPARAM lParam);
    	LRESULT OnMessageHandlerStatus( LPARAM lParam);
    	// Message Handler to allow launcher thread retreiving number of allowed threads
    	LRESULT OnMessageHandlerGetMaxThreads();
    	// Agent settings to use for deploying, either Windows or Unix settings
    	CAgentSettings * m_pSettings;
    	// List of computer to setup
    	CStringList * m_pComputerList;
    	// List of computer where setup failed
    	CStringList m_FailedList;
    	// Thread used to launch setup thread for each computer
    	CWinThread* m_pThreadLauncher;
    	// Max simultaneous connections
    	UINT m_uMaxThreads;	
    };

    enfin voici le processus appeler (toujoru dans deploy.cpp)

    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    UINT InstallComputerList( LPVOID pParam)
    {
    		LPITEMIDLIST	pMyIdList = NULL;
    	LPMALLOC		pIMalloc;
    	CStdioFile		myFile;	
    	CObArray		threadHandles; // List of running threads
    	CLauncherThreadParam* CLpParam = (CLauncherThreadParam *)pParam;
     
    	try
     	{
    		CAgentSettings	*pSettings = ((CLauncherThreadParam *)pParam)->GetSettings();
    		CStringList		*pComputers = ((CLauncherThreadParam *)pParam)->GetComputersList();
    		CStringList		*pFailed = ((CLauncherThreadParam *)pParam)->GetFailedList();
    		CString			csComputer,	// Computer to setup
    						csSuccess,	// String to format number of sucess or failure
    					    csLocalDir,	// Local directory where to find setup.sh
    						csFailure;	
    		POSITION		pos;		// Position into string list
     
    		int				nIndex,		// Number of computer launched
    						nThread;	// Number of threads
    		DWORD			dwErr;
    		CWorkerThreadParam myParam;	// Parameters to pass to working threads
    		CWinThread*		pThread;	// One working thread
     
     
    				// Launch setup for each computer
    		nIndex = 0;
    		pos = pComputers->GetHeadPosition();
    		while (pos)
    		{
    			// Ensure not too many threads already running
    			nThread = 10;
    			while (threadHandles.GetSize() >= nThread)
    			{
    				// Too many threads lanuched, wait a while
    				Sleep( 500);
    				// Cleaning dead threads if needed
    				nThread = 0;
    				while (nThread < threadHandles.GetSize())
    				{
    					// Get thread status
    					pThread = (CWinThread*)threadHandles.GetAt( nThread);
    					GetExitCodeThread( pThread->m_hThread, &dwErr );
    					if( dwErr != STILL_ACTIVE )
    					{
    						// Clean thread
    						threadHandles.RemoveAt( nThread);
    						delete pThread;
    						nThread --;
    					}
    					nThread ++;
    				}
    				nThread = 10;
    			}
    			// Launch new thread
    			csComputer = pComputers->GetNext( pos);
    			myParam.SetParam(pSettings, pFailed, csComputer, csLocalDir);
    			printf("Host <%s:%i> Debut du deploiment\n", (CStringA)csComputer.GetBuffer(),pSettings->GetServerPort());
    			pThread = AfxBeginThread((AFX_THREADPROC)InstallComputer, &myParam, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
    			threadHandles.Add( pThread);
    			pThread->m_bAutoDelete = FALSE;
    			pThread->ResumeThread();
    			// Set status text on dialogbox
    			nIndex ++;
     
     
    			csSuccess.Format( _T( "%d"), nIndex);
    			csFailure.Format( _T( "%d"), pComputers->GetCount());
     
    			/*csComputer.FormatMessage( IDS_STATUS_RUNNING_DEPLOYMENT, csSuccess, csFailure);
    			cout << csComputer << endl;*/
     
     			// Wait a while before launching next script
    			Sleep( 1000);
    		}
     
    		// Waiting for threads to terminate
    		//csComputer.LoadString( IDS_STATUS_STOP_DEPLOYMENT);
    		// ::SendMessage( hWnd, WM_SETTEXT, IDC_MESSAGE_HANDLER_STATUS, (LPARAM) LPCTSTR( csComputer));
     
    		while (threadHandles.GetSize() > 0)
    		{
    			Sleep( 500);
    			// Cleaning dead threads if needed
    			nThread = 0;
    			while (nThread < threadHandles.GetSize())
    			{
    				// Get thread status
    				pThread = (CWinThread*)threadHandles.GetAt( nThread);
    				GetExitCodeThread( pThread->m_hThread, &dwErr );
    				if( dwErr != STILL_ACTIVE )
    				{
    					// Clean thread
    					threadHandles.RemoveAt( nThread);
    					delete pThread;
    					nThread --;
    					//printf("Host <%s:%i> Fin du deploiment\n", (CStringA)csComputer.GetBuffer(),pSettings->GetServerPort());
    				}
    				nThread ++;
    			}
    		}
     
    		if (pFailed->GetCount() == 0)
    		{
    			// No error
    			return 0;
    		}
    		else {
    			//errors
    		return 1;
    			}
     
    	}
    	catch( CException *pEx)
    	{
     
    		return 1;
    	}
    }
    enfin voici CLauncherThreadParam.h

    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
     
    class CLauncherThreadParam  
    {
    public:
    	CLauncherThreadParam();
    	virtual ~CLauncherThreadParam();
     
    	void SetParam(CAgentSettings *pSettings, CStringList *pComputers, CStringList *pFailed);
    	CAgentSettings * GetSettings();
    	CStringList * GetComputersList();
    	CStringList * GetFailedList();
     
    protected:
    	CAgentSettings *m_pSettings;
    	CStringList *m_pComputers;
    	CStringList *m_pFailed;
    };
    Donc le code compile parfaitement, l'exécution ne ose apparament pas de soucis si ce n'est le fait que le pointeur contient des données éronnées lors que le thread InstallComputeurList est appelé.

    Je ne comprend pas d'où viens l'erreur, j'ai fais essayer le code a un collègue bizarrement chez lui ca marche une fois sur deux (CF pièces jointes)


    D'avance merci.
    Mathieu.
    Images attachées Images attachées   

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Bonjour,
    Une fois sur 2 le code de ton collègue déroule le script en moins d'une seconde

    En fait le problème est dans le passage des paramètres : myParam est local à InstallComputerList (elle est sur le tas). A chaque fois que tu créés un thread, tu lui donne la même adresse comme paramètre. Donc, lorsque tu modifie myParam pour le second thread, tu écrases les valeurs utilisées par le premier thread et à un moment que tu ignores. C'est pour cela que rien ne fonctionne. En fait, tous tes threads accèdent au même jeu de paramètre que tu modifies au fur et à mesure que tu lances les threads. Et cela doit être encore pire si InstallComputerList modifie ces paramètres.

    A mon avis, tu devrais commencer par revoir ce qui est partagé ou pas, prévoir d'éventuel verrou si des données sont partagées par plusieurs threads (c'est à dire qu'un thread peut éventuellement en modifier alors qu'un autre le lit), et encapsulé ta gestion de threads et ses paramètres dans une classe dédiée.

  3. #3
    Membre à l'essai
    Inscrit en
    Juillet 2007
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 11
    Points : 11
    Points
    11
    Par défaut
    Merci pour ta réponse archi, j'ai également faits des recherches sur le code sur lequel je me base.

    myParam.SetParam(m_pSettings, m_pComputerList, &m_FailedList);

    m_pSettings, m_pComputerList sont des pointeur vers des objet definit dans mon main, il semblerait que mon soucis vienne que le main attend pas la fin des processus fils pour s'arrêter et donc le garbage collector fait son oeuvre et libère la mémoire prise par mon main, seulement mes thred fils se base sur une adresse mémoire pour aller chercher leurs infos donc si cette adresse est vidé avant que il l'atteigne c'est sur que ce qui sera récupéré ne sera pas bon.


    Maintenant concernant ce que tu me dis, mes threads ne font que lire les parametres sans jamais les modifiés. Le principe du programme c'est que installcomputeurlist survveille les threads (toujour un nombre x en cour) et installcomputeur est le thread lancé par installcomputeurlist pour chaqu'un des pc a s'occuper, ce thread doit se connecter au pc y copié des fichier et se deconecté, tout ce dont il a besoin se trouve dans le myparam.


    Pour la séparation des param en classe distincte c'est fait je pense via LauncherThreadParam et WorkerThreadParam(celle ci je ne l'ai pas poster mais on peut noter son utilisation dans mes citations de code) qui stocké les pointeur vers les item de parametrage.


    Maintenant pour les verrou vu que il n'y a pas de modif sur ce qui est partager je ne pense pas que il soit nécéssaire, et pour l'encapsulation de la gestion thread et des parametre je suppose que tu me conseille d'utilisé une classe autre que le main qui contiendra les process et leur focntion de lancement (si c'est ça c'est deja le cas et c'est les bout de code posté au dessus, mon main cré un objet deploy et appel les différente fonction dont startup qui lance le process InstallComputeurList)

    Une solution que j'ai tester est de faire un seulement une fois le timer passé le programme plante mais les thread fils continue sans soucis.

    Merci de l'aide apporté.

    Cordialement
    Mathieu.

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    L'idée c'est d'associer les paramètres d'un thread à sa durée de vie. Une solution peut consister à avoir ta class CMonThread qui contient les paramètres par valeur et qui se détruit à la fin de l'exécution du thread.
    Pour synchroniser ton thread principal avec les autres threads, tu as les fonctions d'attente (WaitForMultipleObjectsEx).
    Quand à ne pas protéger les accès aux paramètres parce qu'ils ne sont accédés qu'en lecture, c'est prendre le risque d'une race condition un jour ou l'autre car l'expérience montre que tout logiciel finit par évoluer différemment de ce qu'on présumait

  5. #5
    Membre à l'essai
    Inscrit en
    Juillet 2007
    Messages
    11
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 11
    Points : 11
    Points
    11
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    L'idée c'est d'associer les paramètres d'un thread à sa durée de vie. Une solution peut consister à avoir ta class CMonThread qui contient les paramètres par valeur et qui se détruit à la fin de l'exécution du thread.
    Pour synchroniser ton thread principal avec les autres threads, tu as les fonctions d'attente (WaitForMultipleObjectsEx).
    Quand à ne pas protéger les accès aux paramètres parce qu'ils ne sont accédés qu'en lecture, c'est prendre le risque d'une race condition un jour ou l'autre car l'expérience montre que tout logiciel finit par évoluer différemment de ce qu'on présumait

    entendu je vais zieuter de ce coter la, mon soucis principale concernant mon poste est résolus (le passage de parametre marche amitnenant mais j'ai des soucis avec le timer)

    Je vais ouvrir un autre sujet

    Merci pour tes conseil et ton aide

    Cordialement
    Mathieu.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Thread / Passage de parametres
    Par Tlams dans le forum Général Python
    Réponses: 3
    Dernier message: 04/09/2013, 11h15
  2. Thread et passage de parametre
    Par olibara dans le forum C#
    Réponses: 12
    Dernier message: 29/11/2011, 13h35
  3. Réponses: 4
    Dernier message: 04/09/2007, 13h13
  4. Passage de parametre calculé
    Par soazig dans le forum MS SQL Server
    Réponses: 12
    Dernier message: 06/06/2003, 16h25
  5. Passage de parametre a une anim Flash 5
    Par debug dans le forum Intégration
    Réponses: 4
    Dernier message: 03/06/2002, 17h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo