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

MFC Discussion :

Appel à un Thread à partir d'une fonction Timer


Sujet :

MFC

  1. #1
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut Appel à un Thread à partir d'une fonction Timer
    Bonjour,

    Voici un appel a une thread mais a partir d'une fonction OnTImer:

    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
     
    //Dlg_2.cpp
     
     
        / / Global variables
       CDlg_2 * pDlg2; 
     
        UINT MyThreadProc (pParam LPVOID) 
       ( 
     
        pDlg2-> OnButtonBegin (); / / MFC fonction 
     
        return 0; 
       ) 
     
    ....
     
     
    void CDlg_2::OnTimer(UINT nIDEvent) 
    {
     
        if (nIDEvent ==3)  //	
        {	
     
                AfxBeginThread (MyThreadProc, NULL); 
        }
     
     
    ...
     
    }
     
    void CDlg_2::OnButtonBegin() 
    {
    	// TODO: Add your control notification handler code here
     
    	CWaitCursor();
     
    	SHELLEXECUTEINFO sei5;
    	DWORD dw;
     
    	KillTimer(3);
     
    	GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);
     
    	if (process_0)
    	{
     
    					process_0 =false;
    					process_1= true;
     
    	}
    	else if (process_1)
    ..
     
    }

    Quand le programme arrive à cette ligne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pDlg2-> OnButtonBegin (); / / MFC fonction
    Puis j'ai debug assertion failed erreur avec CWnd:: KillTimer (nIDEvent int) Pourquoi ?
    Est ce du au fait que j'appel a aprtir d'une fonction TImer ou bien car la fonction thread est une fonction statique et qu'il y a des fonctions MFC dans la fonction OnButtonBegin() est ce la raison ?

    Y a t il est une autre façon d'appeler un thread dans un Timer?

    Merci

  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
    Salut,
    Les MFCs (en particulier ce qui a trait aux fenêtres et au GDI) se marient mal avec le multithread. En général, quand il s'agit d'agir sur l'I.H.M. avec un thread de travail, je préfère envoyer des messages et n'avoir dans le thread de travail aucune interaction directe avec les éléments d'I.H.M.

  3. #3
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut
    Salut,

    Merci donc du multithread avec envoi de messages permettrait aussi d'avoir un control total sur des elements MFC de l' IHM (button, bar progress, etc... ) ?

    C'est quand même dommage vu que la thread est appellé avec un fonction MFC (AfxBeginThread(...) )

    Est si par contre in créait des fonctions thread non static mais propre au projet MFC serait ce possible dans ce cas d'agir sur des controls MFC dans ces fonctions thread?



    Merci

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 153
    Points : 12 264
    Points
    12 264
    Par défaut
    Le "problème" n'est pas dans les MFC, c'est au niveau des objets fenêtre du Kernel que des choix dictées par les performances ont interdit l'accès aux données des fenêtres dans des threads n'ayant pas créés la fenêtre.

  5. #5
    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
    Citation Envoyé par Aliveli Voir le message
    Est si par contre in créait des fonctions thread non static mais propre au projet MFC serait ce possible dans ce cas d'agir sur des controls MFC dans ces fonctions thread?
    A confirmer, mais il me semble que le problème vient de ce que les objets MFC d'I.H.M. (fenêtre, bts de dialogues, ctrl...) sont construit dans l'espace de stockage du thread qui les créé (Thread Local Storage). Qui plus est, ces objets ne sont pas protégés contre des accès concurrent -> situation de compétition potentielle.
    Donc, je continue de penser que dans beaucoup de cas l'envoi de message reste une solution maitrisée et adaptée.

  6. #6
    Membre éprouvé
    Avatar de Gabrielly
    Inscrit en
    Juin 2004
    Messages
    722
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 722
    Points : 1 128
    Points
    1 128
    Par défaut
    Salut,
    Les MFCs (en particulier ce qui a trait aux fenêtres et au GDI) se marient mal avec le multithread. En général, quand il s'agit d'agir sur l'I.H.M. avec un thread de travail, je préfère envoyer des messages et n'avoir dans le thread de travail aucune interaction directe avec les éléments d'I.H.M.
    Affirmation fausse

    Si le AfxBeginThread existe dans les MFC elle doit nécessairement servir à quelque chose.

    Dans les MFC nous avons 2 types de thread :
    1. Les threads de travail ( fournir une méthode globale ou statique pour cela)
    2. Les threads d'interface utilisateur (fournir un objet CWinThread pour cela)

    Si un thread veut travailler avec des éléments du GUI le deuxième type de thread est là pour ça.

    Le "problème" n'est pas dans les MFC, c'est au niveau des objets fenêtre du Kernel que des choix dictées par les performances ont interdit l'accès aux données des fenêtres dans des threads n'ayant pas créés la fenêtre.
    +1

  7. #7
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 153
    Points : 12 264
    Points
    12 264
    Par défaut
    cf. ma réponse précédente.
    La limitation n'est pas dans les MFC mais dans le système de fenêtrage du Kernel.
    La différence entre les types de thread MFC est liée aux données TLS utilisées par les MFC pour gérer les fenêtres que le thread crée, il n'y a pas de partage de fenêtre entre les différents threads MFC d'interface utilisateur, c'est juste pour que le thread puisse créer simplement des fenêtres gérables par les MFC.

  8. #8
    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
    Citation Envoyé par Gabrielly Voir le message
    Affirmation fausse
    Merci de faire l'effort de lire ce qui a été dit et de se renseigner un peu. Oui on peut utiliser des MFCs dans les threads. Non les objets CWnd and co ne se partagent pas bien. Merci de relire l'entrée de la F.A.Q. Comment travailler sur des objets MFC à partir d'un thread de service ? :
    Citation Envoyé par F.A.Q.
    Donc bien retenir la règle suivante :
    On ne peut pas partager des objets MFC liés aux fenêtres ou d'objets GDI entre plusieurs threads de service.
    On passera le handle de fenêtre en paramètre dans la fonction AfxBeginThread pour établir le lien avec la fenêtre de traitement.
    MSDN :
    For size and performance reasons, MFC objects are not thread-safe at the object level, only at the class level. This means that you can have two separate threads manipulating two different CString objects, but not two threads manipulating the same CString object.
    Et :
    As a general rule, a thread can access only MFC objects that it created. This is because temporary and permanent Windows handle maps are kept in thread local storage to help maintain protection from simultaneous access from multiple threads. For example, a worker thread cannot perform a calculation and then call a document's UpdateAllViews member function to have the windows that contain views on the new data modified. This has no effect at all, because the map from CWnd objects to HWNDs is local to the primary thread. This means that one thread might have a mapping from a Windows handle to a C++ object, but another thread might map that same handle to a different C++ object. Changes made in one thread would not be reflected in the other.

    There are several ways around this problem. The first is to pass individual handles (such as an HWND) rather than C++ objects to the worker thread. The worker thread then adds these objects to its temporary map by calling the appropriate FromHandle member function. You could also add the object to the thread's permanent map by calling Attach, but this should be done only if you are guaranteed that the object will exist longer than the thread.

    Another method is to create new user-defined messages corresponding to the different tasks your worker threads will be performing and post these messages to the application's main window using :ostMessage. This method of communication is similar to two different applications conversing except that both threads are executing in the same address space.
    Sources M.S.D.N. : Multithreading: Programming Tips

  9. #9
    Membre éprouvé
    Avatar de Gabrielly
    Inscrit en
    Juin 2004
    Messages
    722
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 722
    Points : 1 128
    Points
    1 128
    Par défaut
    Ce que je te reproche c'est ta première réponse brutale qui dit que les MFC se marie mal avec le multithread.

    Pour ce qui est des principes je les connais et je suis tout à fait d'accords avec toi. Chaque thread est responsable des objets qu'il a crée.

    Mais il y a une chose que je veux te dire et je le dis par expérience.

    Un thread de travail peut intéragir avec les éléments de l'HIM du thread principale si le thread travail sait obtenir les handles de ces fenêtres et ainsi poster des messages. Bien sûr ce thread auxiliaires doit tenir compte de la durée de vie de l'IHM et des accès concurrents.

  10. #10
    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
    Citation Envoyé par Gabrielly Voir le message
    Ce que je te reproche c'est ta première réponse brutale qui dit que les MFC se marie mal avec le multithread.
    En l'occurrence, c'est le cas : le nombre de bugs que j'ai vu parce qu'on avait échangé des instances d'objets -entre autres IHM (CWnd, CDialog,CEdit...) - entre des threads... C'est une erreur récurrente. La preuve en est la question de départ. Donc, je reste sur mon affirmation : les MFC c'est très bien pour un certain nombre de choses, mais échangé des instances MFC entre des threads IHM ou pas, c'est du bug assuré.
    Citation Envoyé par Gabrielly Voir le message
    Mais il y a une chose que je veux te dire et je le dis par expérience.
    Je te rassures, de l'expérience sur les MFCs on peut en avoir depuis, de mémoire, la version 1.5, de Visual C++ pour Windows 3.1.
    Citation Envoyé par Gabrielly Voir le message
    Un thread de travail peut intéragir avec les éléments de l'HIM du thread principale si le thread travail sait obtenir les handles de ces fenêtres et ainsi poster des messages. Bien sûr ce thread auxiliaires doit tenir compte de la durée de vie de l'IHM et des accès concurrents.
    Je pense que c'est ce que dit l'entrée de la F.A.Q à laquelle je faisais référence : partager des HANDLE et utiliser des messages.

  11. #11
    Membre éprouvé
    Avatar de Gabrielly
    Inscrit en
    Juin 2004
    Messages
    722
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 722
    Points : 1 128
    Points
    1 128
    Par défaut
    Citation Envoyé par 3DArchi
    En l'occurrence, c'est le cas : le nombre de bugs que j'ai vu parce qu'on avait échangé des instances d'objets -entre autres IHM (CWnd, CDialog,CEdit...) - entre des threads... C'est une erreur récurrente. La preuve en est la question de départ. Donc, je reste sur mon affirmation : les MFC c'est très bien pour un certain nombre de choses, mais échangé des instances MFC entre des threads IHM ou pas, c'est du bug assuré.
    Hmmm...
    Pour éviter des bugs assurés il faut faire attention de ne pas échangé n'importe comment et n'importe où. ça dépend de la façon dont on programme aussi et de son talent en programmation.
    Ce que moi j'affirme est qu'il est possible de transmettre tout un objet MFC à un thread qui ne l'a pas crée.
    Mais il faudra être prudent sur les méthodes qui doivent être invoquées sur cet objet qui seront utilisées dans le thread de travail. Ces méthodes ne doivent en aucun cas faire intervenir les éléments du GUI de façon directe.

    Je m'explique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class CMyThreadWnd public CWnd
    {
    //....
    public:
        void MyRegularMethod();             // méthode qui utilise directement un élément du IHM à partir du thread principale
        void MyWorkerThreadMethod();    // méthode qui utilise indirectement le même élément du IHM à partir du thread de travail
        LRESULT OnMyWorkerThreadMethod(WPARAM wp, LPARAM lp);  // méthode compagne du MyWorkerThreadMethod()
     
    //...
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void CMyThreadWnd::MyRegularMethod()
    {
     
           int nItem = 0;
           CString strItemText = "Coucou";
           int nImage = 1;
     
           m_ListCtrl.InsertItem(nItem, strItemText, nImage);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void CMyThreadWnd::MyWorkerThreadMethod()
    {
     
           int nItem = 0;
           static CString strItemText;
           strItemText = "Coucou";
           int nImage = 1;
     
           WPARAM wp = nItem;
           LPARAM lp = (LPARAM)(LPCTSTR) strItemText;
           SendMessage(WM_INSERT_ITEM_IN_MAIN_THREAD, wp, lp);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    LRESULT CMyThreadWnd::OnMyWorkerThreadMethod(WPARAM wp, LPARAM lp)
    {
           int nItem = (int) wp;
           CString strItemText = (LPCSTR) lp;
           int nImage = 1;
     
           m_ListCtrl.InsertItem(nItem, strItemText, nImage);
    }
    m_ListCtrl est une CListCtrl remplit à partir du worker thread. L'objet CMyThreadWnd est transmit comme paramêtre à AfxBeginThread en plus du point d'entré du thread.

    Voici deux copies d'écrans pour les progresses bars controles.

    Un worker thread lancé par boîte de dialogue de progression d'où au moins 5 threads + le thread principale


    Un worker thread lancé par boîte de dialogue de progression d'où au moins 6 threads + le thread principale

    Mais comme tu le dis la programmation multithread est rigoureuse et je suis d'accord avec toi. d'où ma petite contribution à la FAQ

    [FAQ VC++]Comment créer un thread d'interface utilisateur?

  12. #12
    Membre éprouvé
    Avatar de Gabrielly
    Inscrit en
    Juin 2004
    Messages
    722
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 722
    Points : 1 128
    Points
    1 128
    Par défaut
    Et donc pour revenir au problème de Aliveli
    son OnButtonBegin() est appelé dans le thread de travail or OnButtonBegin()
    utilise directement un élément de l'IHM le KillTimer(3) et GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     UINT MyThreadProc (pParam LPVOID) 
       ( 
     
        pDlg2-> OnButtonBegin (); / / MFC fonction 
     
        return 0; 
       )
    donc OnButtonBegin() est semblable à MyWorkerThreadMethod();

    ensuite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void CDlg_2::OnButtonBegin() 
    {
    	//...
     
    	KillTimer(3);
    	
    	GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);
     
    	//...
    }
    ces portions de code ne doivent pas être utilisé de la sorte car ils sont dans le worker thread d'où plantage direct et assuré ==> violation des principes: le worker thread n'a pas crée la dialog pour faire directement un KillTimer() il n'a pas pas non plus créer les boutons pour faire un EnableWindow()

    Un petit remède serait un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void CDlg_2::OnButtonBegin() 
    {
    	//...
     
    	SendMessage(WM_FAIT_POUR_MOI_LE_KILL_TIMER);
                 SendMessage(WM_DESACTIVE_POUR_MOI_LE_BOUTON);
    	//...
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void CDlg_2::JefaisPourToiLeKillTimer(WPARAM wp, LPARAM lp) 
    {
    	KillTimer(3);
                 return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void CDlg_2::JeDesactivePourToiLeBouton(WPARAM wp, LPARAM lp) 
    {
    	GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);
                 return 0;
    }
    Voilà un petit remède

  13. #13
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut
    Merci,

    Mais voici mon code qui a changé la thread est différente mais le résultat ne change pas mon appli se bloque toujours meme quand j'utilise pas les fonctions : KillTimer(3); et GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);

    Je vais quand même poster mon code (eventuellement voir le post Thread et Timer en parallèle et probleme de mis a jour control bar-progress ) :

    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
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
     
     
    BOOL CDlg_2::OnInitDialog() 
    {
    	CDialog::OnInitDialog();
     
    	....
     
     
    	//MessageBox("start the thread");
    	THREADINFOSTRUCT *tis=new THREADINFOSTRUCT;
     
    	tis->hWnd=m_hWnd;
    	tis->someData="This is in a thread.";
     
     
    	CWinThread *pThread = AfxBeginThread(MyThreadFunc,tis,
    	THREAD_PRIORITY_NORMAL,0,0);  // THREAD_PRIORITY_NORMAL THREAD_PRIORITY_HIGHEST
     
    	connected =false;
    	SetTimer(3,1000,0);
        GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);  
     
    	return TRUE;  // return TRUE unless you set the focus to a control
    	              // EXCEPTION: OCX Property Pages should return FALSE
    }
     
     
    void CDlg_2::OnTimer(UINT nIDEvent) 
    {
        if (nIDEvent ==3) //timer for progress bar
    	{	
     
    		RedrawWindow();
     
    		if (posprogress2==100)
    		{
    			posprogress2=10;  			
    		}
    		else
    		{
    			posprogress2+=10;
    		}
     
    		m_progress2.SetPos(posprogress2);
     
    		if ((connected==1) && (already_pass==false))
    		{
    			m_progress2.SetPos(0);
    			first_msg =false;
    			m_static_msg1.SetWindowText(NULL);
    			already_pass =true;
     
    			KillTimer(3);//091008
    		}
    		else if (forcetest==0)
    		{
     
    	//	OnButtonBegin();  //mis dans la thread
    		SetTimer(3,300,0);
    		}
     
    	}
    	UpdateData(FALSE);
    	CDialog::OnTimer(nIDEvent);
    }
     
     
     
    // thread 
    UINT MyThreadFunc(LPVOID lParam)
    {
    	THREADINFOSTRUCT* tis=(THREADINFOSTRUCT*)lParam;
     
     
    	if(wrong_exit==true)
    	good_finish ==true;
     
    	while(good_finish==false)
    	{
    		int i=3;
    		SendMessage(tis->hWnd,WM_USER_THREAD_UPDATE_PROGRESS,i,100);  //SendMessage  PostMessage
    		//DoEvents();
    		Sleep(1500); //
     
    	}
     
    	if(good_finish ==true)
    	PostMessage(tis->hWnd,WM_USER_THREAD_FINISHED,0,0);
     
    	delete tis;
    	return 0;
    }
     
    LRESULT CDlg_2::OnThreadFinished(WPARAM wParam,LPARAM lParam)
    {
    //AfxMessageBox("Thread has exited");
    return 0;
    }
     
    LRESULT CDlg_2::OnThreadUpdateProgress(WPARAM wParam,LPARAM lParam)
    {
    	//m_progress2.SetPos(100*(int)wParam/(int)lParam);
    	RedrawWindow();
     
            /*
    		if(progressindex ==100)
    			progressindex=0;
    		else
    			progressindex+=10;
     
     
    		m_progress2.SetPos(progressindex);
    		*/
    	OnButtonBegin() ;
     
    	return 0;
    }
     
    void CDlg_2::OnButtonBegin() 
    {
    	// TODO: Add your control notification handler code here
    	CWaitCursor();
     
    	SHELLEXECUTEINFO sei5; 
    	DWORD dw;  
     
    	GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false);
     
    	if (process_0)
    	{
    		process_0 =false;
    		process_1= true;
    	}
    	else if (process_1)
    	{
         //try
    		{
    		connected=cp.Init("192.0.2.2"); //Fonction qui pose probleme
    		}
     
    	//	catch(...)
    		{
    				//MessageBox("Problem of Init", "Exception Message");
     
    		}
    		if (connected==1)
    		{
    						process_1 =false;
    						process_2= true;
            }
    	}
    	...
     
    }
    Merci

  14. #14
    Rédacteur
    Avatar de farscape
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2003
    Messages
    9 055
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2003
    Messages : 9 055
    Points : 17 323
    Points
    17 323
    Par défaut
    salut,
    Citation Envoyé par Faq
    Notes: La fonction thread peut être définie dans une classe si elle est déclarée statique.
    Dans le cas d'utilisation conjointe avec des boîtes de dialogue modales, il est préférable de poster (PostMessage) le message plutôt que de l'envoyer (SendMessage), afin d'éviter un problème de réentrance avec la pompe à messages du thread principal.
    quel est la classe correspondant à l'objet cp : cp.Init ?

  15. #15
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut
    Il s'agit d'une classe d'une libraire pour une camera:

    fxCamPrev cp;

    cette classe encapsule d'ailleurs une autre classe :fxcam (#include "fxcam.h") et ainsi de suite mais a la base il y a qu'un seule fonction gx(,,,) avec differents parametres ou surcharges.

    Je pense que le probleme vient de reconnect , j'ai mis le code ci dessous:

    Avec Init qui est la methode de fxCamPrev
    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
     
     
    bool fxCamPrev::Init(const char *_devname) {
    	time_t tt;
    	time(&tt);
    	struct tm *lt = localtime(&tt);
    	AppendLog("%04u-%02u-%02u %02u:%02u:%02u  Program started\n",
    	lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday,
    	lt->tm_hour, lt->tm_min, lt->tm_sec);
     
    	devname = _devname ? strdup(_devname) : (char *)0;
     
     
    	bool ici=LoadSettingsFromFile();
    	if (ici=true)
    		TRACE("OK load file settings");
    	else
    		TRACE("NOK load file settings");
     
    	// Connecting to the camera
    	bool st = Reconnect(true);
    	if(!st) return false;
     
     
    	return true;
    }
    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
     
    bool fxCamPrev::Reconnect(bool force_init) {
    	// Check module
    	if(!fxCamera::IsValid()) {
    		SetGXError("Create camera class failed (possible the fxcam module doesn't exists)");
    		return false;
    	}
     
    	// Connect to the camera
    	if(!fxCamera::Connect(devname)) {
    		SetGXError("Cannot connect camera (%s)", devname ? devname : "FXCAMU, 192.0.2.2:9000");
    		return false;
    	}
     
    	if(!force_init) {
    		// Check the camera. Did it rebooted or only network connection was broken?
    		char camtime[64];
    		memset(camtime, 0, sizeof(camtime));
    		if(fxCamera::GetProperty("connect/camera_timems", camtime, sizeof(camtime)-1)) {
    #ifdef LINUX
    			gxu64 timems = strtoll(camtime, 0, 10);
    #else
    //			gxu64 timems = _strtoui64(camtime, 0, 10);
    			gxu64 timems = strtol(camtime, 0, 10); 
    #endif
    			if(timems > 1000*60*60*24*365*30) {	// 30 years since 1970 (timems > year ~2000)
    				// not reboot -> don't initialize
    				return true;
    			}
    		}
    	}
     
    	// Synchronize the DSP time
    	time_t t;
    	time(&t);
    //	gxu32 t1 = SDL_GetTicks();
    	if(!fxCamera::SetTime(1000*(gxu64)t)) {
    //		SetGXError("SetTime() failed (%u ms)", SDL_GetTicks()-t1);
    		return false;
    	}
     
    	// Get information from the camera
    	gxu32 _program;
    	gxu16 _camera;
    //	t1 = SDL_GetTicks();
    	if(!fxCamera::GetInfo(&_program, NULL, NULL, &_camera)) {
    //		SetGXError("GetInfo() failed (%u ms)", SDL_GetTicks()-t1);
    		return false;
    	}
     
    	// Check firmware version
    	if(_program < 0x01040000) {
    		SetMyError("Program version of the camera is too old %u.%u.%u.%u (required: 1.4.0.0)",
    				(_program >> 24) & 0xFF, (_program >> 16) & 0xFF,
    				(_program >> 8) & 0xFF, _program & 0xFF);
    		return false;
    	}
     
    	if(camer...

    Donc comment faire les threads correctement pour que l'appli ne se fige pas?
    Je suis debutant avec le multithreading ?

    Merci

  16. #16
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut
    Ok,

    Tel que Gabrielly l'a énoncé je dois
    faire des thread séparés pour les 2 fonctions MFC au même titre que
    la grande fonction (OnButtonBegin()) dans un des thread de travail ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    LRESULT CDlg_2::OnThreadUpdateProgress(WPARAM wParam,LPARAM lParam)
    {
    	//m_progress2.SetPos(100*(int)wParam/(int)lParam);
    	RedrawWindow();
     
    	OnButtonBegin() ;
     
    	return 0;
    }
    La thread de travail principale :

    UINT MyThreadFunc(LPVOID lParam)
    {


    }

    Contiendrat quoi alors, devrais je laisser tel que j'avais fait?

    Merci

  17. #17
    Membre du Club
    Profil pro
    Developer
    Inscrit en
    Juin 2004
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Developer

    Informations forums :
    Inscription : Juin 2004
    Messages : 194
    Points : 58
    Points
    58
    Par défaut
    Ok, Ca va mieux mon application ne se fige plus
    en fait l'erreur que j'avais dans mon ancien code ( voir code du post 13 )
    c'est que ma thread contenait la fonction MFC OnButtonBegin ()
    qui lui, Thread principale, appelait la fonction bloquante alors
    c'est normal que l'application se fige.

    Voici le bon code qui lance sur une thread séparée la fonction boquante
    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
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
     
     
    //globales variables
    	//Worker thread
    	#define WM_USER_THREAD_FINISHED (WM_USER+0x100) 
    	#define WM_USER_THREAD_UPDATE_PROGRESS (WM_USER+0x101)
     
    	UINT MyThreadFunc(LPVOID lParam); 
    	int progressindex =0;
     
    	typedef struct THREADINFOSTRUCT {
    	HWND hWnd;
    	CString someData;
     
    	} THREADINFOSTRUCT;
    	//Worker thread
     
    	UINT MyThreadProc(LPVOID pParam);
     
     
    //codes
    BOOL CDlg_2::OnInitDialog() 
    {
    	CDialog::OnInitDialog();
     
    	...
     
     
    	m_progress2.SetRange(1, 100);
    	m_progress2.SetPos(0);
     
    	connected =false;
    	SetTimer(3,100,0);
        GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(false); 
     
    	return TRUE; 
    }
     
     
    LRESULT CDlg_2::OnThreadFinished(WPARAM wParam,LPARAM lParam)
    {
    AfxMessageBox("Thread has exited");
    connected=1;
    return 0;
    }
     
    LRESULT CDlg_2::OnThreadUpdateProgress(WPARAM wParam,LPARAM lParam)
    {
    	//OnButtonBegin() ;
    	return 0;
    }
     
    //Worker thread
    UINT MyThreadFunc(LPVOID lParam)
    {
    	THREADINFOSTRUCT* tis=(THREADINFOSTRUCT*)lParam;
     
    	while(connected!=1)
    	{
    		AfxMessageBox("In the Thread");
     
    		connected=cp.Init("192.0.2.2"); //CHANGES
    		Sleep(1000); //sleep between call blockinfg function
    	}
    	PostMessage(tis->hWnd,WM_USER_THREAD_FINISHED,0,0);
     
    	delete tis;
    	return 0;
    }
     
     
    void CDlg_2::OnTimer(UINT nIDEvent) 
    {
    	// TODO: Add your message handler code here and/or call default
    	UpdateData(TRUE);
     
        if (nIDEvent ==3)  //timer for progress bar
    	{	
    		RedrawWindow();
     
    		if (posprogress2==100)
    		{
    			posprogress2=10;  		
    		}
    		else
    		{
    			posprogress2+=10;
    		}
     
    		m_progress2.SetPos(posprogress2);
     
    		if ((connected==1) && (already_pass==false))
    		{
     
    			m_progress2.SetPos(0);
    			first_msg =false;
    			m_static_msg1.SetWindowText(NULL);
    			already_pass =true;
     
    		}
    		else if (forcetest==0)
    		{
     
    		OnButtonBegin(); //CHANGES
     
    		}
    	}
     
    	UpdateData(FALSE);
    	CDialog::OnTimer(nIDEvent);
    }
     
    void CDlg_2::OnButtonBegin() 
    {
    	// TODO: Add your control notification handler code here
    	CWaitCursor();
     
    	THREADINFOSTRUCT *tis=new THREADINFOSTRUCT; //CHANGES
    	tis->hWnd=m_hWnd;
    	tis->someData="This is in a thread.";
     
     
    	if (process_0)
    	{
    			process_0 =false;
    			process_1= true;
     
    			CWinThread *pThread = AfxBeginThread(MyThreadFunc,tis,
    			THREAD_PRIORITY_NORMAL,0,0);  
    	}
    	else if (process_1)
    	{
    		//try
    			{
     
    				//connected=cp.Init("192.0.2.2"); //
     
    			}
    		//	catch(...)
    			{
    					//MessageBox("Problem of Init Fxcam", "Exception Message");
    					//KillTimer(3);
    					//m_progress2.SetPos(0);
    					//GetDlgItem(IDC_BUTTON_CAMERA2)->EnableWindow(true); 
    			}
    			if (connected==1)
    			{
    							process_1 =false;
    							process_2= true;
     
    							CFont *m_Font_step2_label = new CFont;
    							m_Font_step2_label->CreateFont(14, 0, 0, 0, 700,
    							FALSE, FALSE, FALSE, 900, 
    							OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,   
    							DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, "Verdana");							
    							m_step2_label.SetFont(m_Font_step2_label);
    			}
     
    	}
     
    	else if (process_2)
    	{
    	...
    	}
     
    	...
    	...
    }

    Merci

Discussions similaires

  1. Argument d'appel de procédure à partir d'une fonction
    Par electrosat03 dans le forum VBA Access
    Réponses: 4
    Dernier message: 30/03/2008, 17h33
  2. Réponses: 4
    Dernier message: 30/11/2007, 14h46
  3. Réponses: 2
    Dernier message: 20/06/2007, 12h12
  4. Appeler une nouvelle fenetre à partir d'une fonction callback
    Par foxyman dans le forum GTK+ avec C & C++
    Réponses: 4
    Dernier message: 02/02/2007, 18h42
  5. Réponses: 1
    Dernier message: 09/08/2006, 16h04

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