begin process at 2012 05 29 21:30:01
  Trouver un code source :
 
dans
 
Accueil > Forum > 

Archive C/C++

 > 

Archives

 > 

Au secours

 > 

problème multithreading pourtant simple sous Visual C++ & MFC


Derniers messages déposésPoser une question dans le forum ou lancer une discussion

problème multithreading pourtant simple sous Visual C++ & MFC

mercredi 1 septembre 2004 à 01:40:06 | problème multithreading pourtant simple sous Visual C++ & MFC

kelly

Au secours !
Je m'arrache les cheveux depuis des jours en essayant de comprendre d'ou vient le probleme :

Mon application dispose de boutons type magnétophone : Play, Pause, Stop.

Un clic sur PLAY lance un thread, jusque là aucun probleme.

Un clic sur STOP devrait signaler au thread précédemment lancé qu'il est temps pour celui-ci de se terminer.
Pour ce faire, la fonction exécutée par le clic sur STOP change l'état d'une variable booleenne globale : m_PleaseStop=true.

La thread PLAY vérifie à chaque tour de boucle (c'est un algo qui tourne en boucle) la valeur de m_PleaseStop. Quand m_PleaseStop==true, la fonction de la thread PLAY se dirige vers la sortie et juste avant de finir, réaffecte m_PleaseStop=false, pour la forme.

Bref, mon problème est que mon programme se bloque de manière aléatoire quand PLAY est en route et que je clique sur STOP (la boucle PLAY s'arrete effectivement puis je n'ai plus la main, la thread étant toujours existante).

J'ai remarqué qu'en éliminant une ligne UpdataData(false) présente dans la boucle PLAY, le problème disparait et tout fonctionne normalement, la thread PLAY se ferme et tout va bien.

J'ai alors essayé de mettre des sections critiques, des temporisations etc. mais rien n'y fait, et quoi de plus normal puisque la procédure STOP n'utilise aucun objet spécial.

Je ne comprends pas, aidez moi SVPPPPPPPPPP !
mercredi 1 septembre 2004 à 01:56:42 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

AlexMAN

Membre Club
Je sais pas si ca pourrait marcher, mais essaye, sait on jamais :

#define WM_ENDTHRPLAY WM_USER + 1

int Stop (...)
{
...
PostMessage(hwnd, WM_ENDTHRPLAY, 0, 0);
...
}

LRESULT CALLBACK WndProc(...)
{
...
case WM_ENDTHRPLAY:
TerminateThread(hthreadplay);
CloseHandle(hthreadplay);
return 0;
...
}

Vraiment po sur de la fonctionnalité du code ci dessus, teste et envoie nous une réponse ;)

Allez, bonne nuit a toi

++
mercredi 1 septembre 2004 à 11:07:39 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

BruNews

Administrateur CodeS-SourceS
AlexMAN, c'est du MFC son affaire. Jamais de TerminateThread(), c'est une fonction d'extreme urgence qui engendrerait des enormes fuites memoire. Son thread doit finir proprement.

ciao...
BruNews, Admin CS, MVP VC++
mercredi 1 septembre 2004 à 11:16:38 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

AlexMAN

Membre Club
Je sais que TerminateThread ne doit pas etre utilisé (libere pas les ressources...etc), faut il utiliser ExitThread a la place ?
mercredi 1 septembre 2004 à 11:17:37 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

AlexMAN

Membre Club
Et dsl, j'avais pas vu que c'etait du MFC, dsl.
mercredi 1 septembre 2004 à 22:51:04 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

kelly

La méthode d'Alexman doit en effet fonctionner et je l'en remercie, mais c'est vrai que si je trouvais le moyen de terminer la thread proprement (par sa propre volonté) , ca m'arrangerait...

Je répète cependant mon observation sur le comportement de mon code : si je supprime les appels UpdateData(false) réalisés par la thread PLAY, tout fonctionne comme sur des roulettes...

Mes threads freezent sur des UpdateData(false) quoi... et il n'y a meme pas de section critique ou autre à mettre en oeuvre puisque STOP ne demande rien au systeme ! pourquoi ? pourquoi moi ??
mercredi 1 septembre 2004 à 22:57:35 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

BruNews

Administrateur CodeS-SourceS
Tu ne serais pas en MFC j'y aurais jete un oeil mais la desole...
Faut bien remonter toutes les actions engendrees par UpdateData(false) dans ton code, y a que ça a faire.

ciao...
BruNews, Admin CS, MVP VC++
jeudi 2 septembre 2004 à 12:32:09 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

ymca2003

je suppose que tu passe en param de ton thread un pointeur sur le CDialog et que tu utilise ce pointeur pour faire UpdateData.

voici ce qui est dit dans les sources MFC :

"wincore.cpp" ligne 886
void CWnd::AssertValid() const

// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.

en gros, dans le thread il faut éviter d'utiliser des fonctions spéciales MFC et n'utiliser que les fonctions API déguisées (implémentée en inline avec le HWND implicite).
jeudi 2 septembre 2004 à 18:50:07 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

kelly

Merci quand meme Brunews!
-> ymca2003 : En effet, c'est très exactement la manipulation que j'ai faite. D'ailleurs si je compile en debug, une librairie interne responsable de UpdateData crie (assertion invalide) que la classe appelante n'est pas la meme que le CDialog dont je veux rafraichir le contenu des controles standards (je détaille au cas ou qqun d'autre est intéressé par le probleme). Ce qui est bizarre puisque l'appel se présente comme suit :

Appel lors du clic sur PLAY :

void CMonAppDlg::OnBRestart()
{
...
AfxBeginThread( g_PseudoThreadFunction, (LPVOID)this ) ;
}


Pseudo fonction thread définie en global :
UINT g_PseudoThreadFunction(LPVOID pParam)

{
((CMonAppDlg*)pParam) -> m_ThreadFunc() ;
return 0 ;
}


Fonction thread effectivement appelée :

void CMonAppDlg::m_ThreadFunc()
{
...
UpdateData(false) ;
...
return ; // ferme proprement le thread en remontant les appels
}


D'ou vient alors cette assertion invalide ?
Pourquoi en compilant en release, tout passe bien, et le programme ne freeze d'ailleurs "que" 9 fois sur 10 ?
Une chose est sure, le freeze venait d'une routine au plus profond de l'OS.
Merci de me faire encore profiter de tes lumieres !
jeudi 2 septembre 2004 à 22:42:25 | Re : problème multithreading pourtant simple sous Visual C++ & MFC

ymca2003

pour t'en sortir, il suffit d'associer chacun des contrôles dont tu as besoin de la boîte de dialogues à leur classe respectives (et pas int , CString ou autre variables).

ensuite, au lieu d'appeler UpdateData, tu te sert de ton pointeur sur le dialogue pour récuper les controles et faire doit même les mises à jour (UpdateData est censé simplifié le travail en associant un CString a un Edit par exemple, mais il est aussi simple d'affecter soi-même le nouveau texte à l'Edit, ex (chrono):



//***************************************************************************************
// MFCThreadDlg.h : header file
//
//***************************************************************************************

#ifndef AFX_MFCTHREADDLG_H_INCLUDED_
#define AFX_MFCTHREADDLG_H_INCLUDED_

//***************************************************************************************
// Classe CMFCThreadDlg.
//***************************************************************************************
class CMFCThreadDlg : public CDialog
{
//=======================================================================================
// Membres privés.
//=======================================================================================
private :

// icone associée à la boîte de dialogue
HICON m_hIcon;

// police de caractère pour l'affichage
CFont* m_pFont;

// heure de départ du chronomètre, offset éventuel à rajouter
DWORD m_dwStartTime;
DWORD m_dwOffsetTime;

// thread du chronomètre, états (m_bThreadRunning est volatile pour que sa valeur
// soit évaluée à chaque boucle et éviter des optimisations du compilateur menant
// à un deadlock)
CWinThread* m_pThread;
BOOL m_bPause;
volatile BOOL m_bThreadRunning;

// synchronisation des threads (pour qu'un seul ai accès aux variables partagées
// à un instant donné)
CRITICAL_SECTION m_cs;

//=======================================================================================
// Méthodes privées.
//=======================================================================================
private :
// met à jour l'état des boutons
void UpdateButtons();

// point d'entrée du thread du chronomètre
static UINT ThreadFunc(LPVOID lpData);

//=======================================================================================
// Méthodes publiques.
//=======================================================================================
public :
// constructeur
CMFCThreadDlg(CWnd* pParentWnd = NULL);

//=======================================================================================
// Données de la boîte de dialogue.
//=======================================================================================
protected :
//{{AFX_DATA(CMFCThreadDlg)
enum { IDD = IDD_MFCTHREAD };
CStatic m_StcCounter;
CButton m_BtnStart;
CButton m_BtnStop;
CButton m_BtnPause;
//}}AFX_DATA

//=======================================================================================
// Méthodes virtuelles redéfinies.
//=======================================================================================
//{{AFX_VIRTUAL(CMFCThreadDlg)
protected :
virtual void DoDataExchange(CDataExchange* pDX);
//}}AFX_VIRTUAL

//=======================================================================================
// Traitement des messages.
//=======================================================================================
protected :
//{{AFX_MSG(CMFCThreadDlg)
virtual BOOL OnInitDialog();
afx_msg void OnBtnStart();
afx_msg void OnBtnStop();
afx_msg void OnBtnPause();
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

#endif // AFX_MFCTHREADDLG_H_INCLUDED_




//***************************************************************************************
// MFCThreadDlg.cpp : implementation file
//
//***************************************************************************************

#include "StdAfx.h"
#include "MFCThread.h"

#include "MFCThreadDlg.h"

//=======================================================================================
// Tables des messages pour CMFCThreadDlg.
//=======================================================================================
BEGIN_MESSAGE_MAP(CMFCThreadDlg, CDialog)
//{{AFX_MSG_MAP(CMFCThreadDlg)
ON_BN_CLICKED(IDC_MFCTHREAD_BTN_START, OnBtnStart)
ON_BN_CLICKED(IDC_MFCTHREAD_BTN_STOP, OnBtnStop)
ON_BN_CLICKED(IDC_MFCTHREAD_BTN_PAUSE, OnBtnPause)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//***************************************************************************************
// Constructeur.
//***************************************************************************************
CMFCThreadDlg::CMFCThreadDlg(CWnd* pParentWnd)
: CDialog(CMFCThreadDlg::IDD, pParentWnd)
{
//{{AFX_DATA_INIT(CMFCThreadDlg)
//}}AFX_DATA_INIT

// initialisation des paramètres
m_pFont = NULL;
m_dwStartTime = 0;
m_dwOffsetTime = 0;
m_pThread = NULL;
m_bThreadRunning = FALSE;
m_bPause = FALSE;

// chargement de l'icone asociée à la boîte de dialogue
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

//***************************************************************************************
// DoDataExchange :
//***************************************************************************************
void CMFCThreadDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMFCThreadDlg)
DDX_Control(pDX, IDC_MFCTHREAD_STC_COUNTER, m_StcCounter);
DDX_Control(pDX, IDC_MFCTHREAD_BTN_START, m_BtnStart);
DDX_Control(pDX, IDC_MFCTHREAD_BTN_STOP, m_BtnStop);
DDX_Control(pDX, IDC_MFCTHREAD_BTN_PAUSE, m_BtnPause);
//}}AFX_DATA_MAP
}

//***************************************************************************************
// UpdateButtons :
//***************************************************************************************
void CMFCThreadDlg::UpdateButtons()
{
// bouton [Démarrer]
m_BtnStart.EnableWindow(m_pThread == NULL);

// bouton [Arrêter]
m_BtnStop.EnableWindow(m_pThread != NULL);

// bouton [Pause\Reprendre]
m_BtnPause.SetWindowText(m_bPause ? _T("Reprendre") : _T("Pause"));
m_BtnPause.EnableWindow(m_pThread != NULL);
}

//***************************************************************************************
// ThreadFunc :
//***************************************************************************************
UINT CMFCThreadDlg::ThreadFunc(LPVOID lpData)
{
// récupération objet CMFCThreadDlg associé
CMFCThreadDlg* pMFCThreadDlg = (CMFCThreadDlg*)lpData;

// tant que le thread doit tourner (m_bThreadRunning est volatile pour que sa valeur
// soit évaluée à chaque boucle et éviter des optimisations du compilateur menant
// à un deadlock. A priori inutile si utilisée à travers un pointeur)
while(pMFCThreadDlg->m_bThreadRunning)
{
// pause de 5 ms
Sleep(5);

// calcul de la nouvelle valeur du chronomètre
EnterCriticalSection(&pMFCThreadDlg->m_cs);
DWORD dwTime = GetTickCount()-pMFCThreadDlg->m_dwStartTime+
pMFCThreadDlg->m_dwOffsetTime;
LeaveCriticalSection(&pMFCThreadDlg->m_cs);

// décomposition des minutes, secondes et centièmes de seconde
int nMinutes = dwTime/60000;
int nSeconds = (dwTime-60000*nMinutes)/1000;
int nHundreth = (dwTime%1000)/10;

// formatage chaîne et affichage (sauf si le thread a été arrêté entre temps)
if(pMFCThreadDlg->m_bThreadRunning)
{
CString strTime;
strTime.Format(_T("%02d:%02d:%02d"), nMinutes, nSeconds, nHundreth);
pMFCThreadDlg->m_StcCounter.SetWindowText(strTime);
}
}
return 0;
}

//=======================================================================================
// Gestionnaire de messages pour CMFCThreadDlg.
//=======================================================================================

//***************************************************************************************
// OnInitDialog :
//***************************************************************************************
BOOL CMFCThreadDlg::OnInitDialog()
{
// appel fonction de la classe de base
CDialog::OnInitDialog();

// affectation des icones (grande et petite)
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);

// création police de caractères (3/4 de la hauteur du CStatic)
CRect rcStcCounter;
m_StcCounter.GetClientRect(&rcStcCounter);
m_pFont = new CFont();
m_pFont->CreateFont(3*rcStcCounter.Height()/4, 0, 0, 0, FW_NORMAL, FALSE, FALSE,
FALSE, ANSI_CHARSET, 0, 0, 0, 0, NULL);

// affectation au contrôle CStatic
m_StcCounter.SetFont(m_pFont, FALSE);

// initialisation section critique
InitializeCriticalSection(&m_cs);

// mise à jour de l'état des boutons
UpdateButtons();

// retour
return TRUE;
}

//***************************************************************************************
// OnDestroy :
//***************************************************************************************
void CMFCThreadDlg::OnDestroy()
{
// destruction de la police de caractères
ASSERT(m_pFont != NULL);
m_pFont->DeleteObject();
delete m_pFont;

// on stoppe le chronomètre
OnBtnStop();

// destruction section critique
DeleteCriticalSection(&m_cs);

// appel fonction de la classe de base
CDialog::OnDestroy();
}

//***************************************************************************************
// OnBtnStart :
//***************************************************************************************
void CMFCThreadDlg::OnBtnStart()
{
// si un thread est déjà en cours
if(m_pThread != NULL)
return;

// heure de début, offset
m_dwStartTime = GetTickCount();
m_dwOffsetTime = 0;

// création d'un nouveau thread (on met m_bAutoDelete car on gèrera la destruction)
m_bPause = FALSE;
m_bThreadRunning = TRUE;
m_pThread = AfxBeginThread(CMFCThreadDlg::ThreadFunc, this,
THREAD_PRIORITY_BELOW_NORMAL, 0, CREATE_SUSPENDED, NULL);
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();

// mise à jour de l'état des boutons
UpdateButtons();
}

//***************************************************************************************
// OnBtnStop :
//***************************************************************************************
void CMFCThreadDlg::OnBtnStop()
{
// si aucun thread en cours
if(m_pThread == NULL)
return;

// arrêt du thread, si le thread était suspendu, on le reprend
m_bThreadRunning = FALSE;
if(m_bPause)
m_pThread->ResumeThread();
m_bPause = FALSE;

// on attend que le thread s'arrête (on traite les messages en attente car le thread
// est susceptible d'envoyer des messages aux contrôles créé par le thread principal)
while(::WaitForSingleObject(m_pThread->m_hThread, 10) != WAIT_OBJECT_0)
{
// traiter les messages en attente
MSG msg;
if(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}

// destruction de l'objet CWinThread
delete m_pThread;
m_pThread = NULL;

// mise à jour de l'état des boutons
UpdateButtons();
}

//***************************************************************************************
// OnBtnPause :
//***************************************************************************************
void CMFCThreadDlg::OnBtnPause()
{
// si aucun thread en cours
if(m_pThread == NULL)
return;

// pause/reprise du thread
if(m_bPause)
{
// on affecte la nouvelle heure de départ
EnterCriticalSection(&m_cs);
m_dwStartTime = GetTickCount();
m_pThread->ResumeThread();
LeaveCriticalSection(&m_cs);
}
else
{
// on sauvegarde la valeur actuelle pour s'en servir d'offset
EnterCriticalSection(&m_cs);
m_pThread->SuspendThread();
m_dwOffsetTime = GetTickCount()-m_dwStartTime+m_dwOffsetTime;
LeaveCriticalSection(&m_cs);
}
m_bPause = !m_bPause;

// mise à jour de l'état des boutons
UpdateButtons();
}






IDD_MFCTHREAD DIALOGEX 0, 0, 250, 110
STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION |
WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "MFCThread"
FONT 8, "MS Sans Serif"
BEGIN
CTEXT "00:00:00",IDC_MFCTHREAD_STC_COUNTER,10,10,230,70,
SS_CENTERIMAGE
PUSHBUTTON "Démarrer",IDC_MFCTHREAD_BTN_START,10,90,50,14
PUSHBUTTON "Arrêter",IDC_MFCTHREAD_BTN_STOP,70,90,50,14
PUSHBUTTON "Pause",IDC_MFCTHREAD_BTN_PAUSE,130,90,50,14
PUSHBUTTON "Fermer",IDCANCEL,190,90,50,14
END



Cette discussion est classée dans : problème, thread, stop, play, pleasestop


Répondre à ce message

Sujets en rapport avec ce message

PROBLEME DE THREAD (CreateThread -->ERROR) [ par neub ] Salut à tous, j'ecris un module de visionnement d'image etje souhaiterai pouvoir stopper ma fonction OnPlay au moment voulu mais j'ai un pb a la creat Problème de boucle dans un muli-thread [ par vinvay ] Alors voila, j'ai 4 threads qui tournent en même temps, ceux-ci utilisant la même fonction.Dans cette fonction, il y a une première boucle for suivie Problème Thread + HElppppppppppppppppppppppppppppppppppp [ par emmanuel9 ] Bonjour à tous, En faite j'ai un tread et je fais une boucle sur une ArrayList de personne et en faite dans la fonction UpdateProgressBar j'aurais b bouton stop [ par rlope ] BonjourJ'ai un petit problème avec un bouton STOP que je voudrais créer. (Visual C++ boite de dialogue)Explication :Avec un bouton de ma boite de dial Thread, Client/Serveur VC++.Net et avec WinForms ( pas d'MFC ) [ par lacousine ] Bonjour,j'ai développé un serveur qui accept plusieurs clients avec des sockets. Voici mes problèmes: lorsque je veux mettre fin à mon serveur et qu'i Problème de .h débutant [ par matt22 ] Bonjour à tous.j'ai quelques notions en c++ mais de gros problème à bien comprendre les .h et comment bien les utiliser.J'avais une application avec j Question sur Thread dans mon serveur multithread [ par Nixeus ] Bonjour a tous !J'ai récupérer un code source d' un serveur multithread multi client, en mode console.J'ai repris les classes et j'ai porté ce program Problème avec un thread [ par Mini92 ] Bonsoir (ou bonjour),J'ai un ti soucis avec un thread, en fait, la fonction qui se trouve à l'intérieur ne s'exécute pas... Je comprend pas, pourtant Problème de fermeture de connexions [ par Mr.X ] Bonjours. Enfait mon problème c'est que lorsque je lance un programme que j'ai créé celui-ci se déroule parfaitement bien. Mais après sa fermeture et


Nos sponsors


Sondage...

CalendriCode

Mai 2012
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Consulter la suite du CalendriCode

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 5,678 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales