Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » VC++ / MFC » Multithreading will nicht

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
05.10.2004, 09:18 Uhr
BAR



Hallo allerseits,

Gestern habe ich den ganzen Tag damit verbracht mein schon fertiges Programm mit Multithreading zum laufen zu bringen weil ich einen Button einfügen wollte der zum abbrechen des Prozesses dient. Ich habe es immernoch nicht geschafft und bin nahe der Erschöpfung

Bei dem Henkesoft Tutorial wurde es so gemacht:

C++:
void CThread001Dlg::OnButtonStart()
{
  m_Flag = 1;
  CWinThread* pThread = AfxBeginThread (thrFunction, this);
}

void CThread001Dlg::OnButtonStop()
{
  m_Flag = 0;
}

UINT CThread001Dlg::thrFunction(LPVOID pParam)
{
  CThread001Dlg* pDlg = (CThread001Dlg*) pParam;
  pDlg->thrRun();
  return 0;
}

void CThread001Dlg::thrRun()
{
  while (m_Flag)
  {
     Sleep(1000);
     MessageBeep(0);
  }
}
Wie man unschwer erkennen kann ruft er in der Thread-Funktion eine ganz normale Funktion der Klasse aus dem Dialog auf. Ich wollte es ähnlich machen:


C++:
void CRouteSortDlg::OnButtonReplacing()
{
    UpdateData(TRUE);

    ...
    CAddFunctions    AF;
    CRecFileFind    RFF(m_strEditDirectoryLocation, ".pt");

    int                nF = 0;
    int                FC = RFF.GetFileCount();
    BOOL            checkFile;
    CString            currentFile;
    CString            output;

    GetDlgItem(IDC_BUTTON_CANCEL)->EnableWindow(TRUE);

    CreateNewDataSource();

    for(nF = 0; nF < FC; nF++)
    {
        ...
        else //IF THE CURRENT FILE IS NOT DAMAGED
        {
            m_Flag = 1;
            CWinThread* pThread = AfxBeginThread(ProcessSeparatingThread, this);
        }
    }

    UpdateData(FALSE);    
}

/**************************************************************************************************************************/
/**************************************************************************************************************************/

UINT CRouteSortDlg::ProcessSeparatingThread(LPVOID pParam)
{
    CRouteSortDlg* pDlg = (CRouteSortDlg*) pParam;

    while(pDlg->m_Flag == 1)
    {
        pDlg->ProcessSeparating();
    }

    return 0;
}

/**************************************************************************************************************************/
/**************************************************************************************************************************/

void CRouteSortDlg::ProcessSeparating()
{
    UpdateData(TRUE);

    while(m_Flag == 1)
    {
        ... //Verdammt lange Funktion. Wenn ich die posten würde würde sich das vermutlich niemand anschauen und sie ist nicht von Belang
    }

    UpdateData(FALSE);
}
Könnte mir jetzt jemand vielleicht sagen warum ich wenn ich den Button drücke die folgenden Fehler bekomme?

Da muss ich etwa 15 Mal auf OK klicken damit es verschwindet
Ein "normaler" Debug Assertion Fehler

An den Funktionen selber liegt es nicht denn die funktionieren ohne Multithreading tadellos, ich muss nur noch das obige hier zum laufen kriegen .

Vielen Dank im Voraus

Dieser Post wurde am 05.10.2004 um 09:19 Uhr von BAR editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
05.10.2004, 09:31 Uhr
proga



vorab schonmal: hast du die Methode ProcessSeparatingThread() als static deklariert? muss du machen, damit diese in einem separaten Thread ausgeführt werden kann.

und welche Fehlermeldung bekommst du denn jetzt genau?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
05.10.2004, 10:12 Uhr
BAR



Hi progra,

Ja, die "Zwischenklasse" ProcessSeparatingThread() ist statisch:

C++:
static UINT        ProcessSeparatingThread(LPVOID pParam);
void            ProcessSeparating();

Zu den Fehlermeldungen: Ich bekomme beide auf den obigen Links

Dieser Post wurde am 05.10.2004 um 10:12 Uhr von BAR editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
05.10.2004, 10:35 Uhr
proga



oh, sorry, übersehen
aber ohne Quellcode kann man diesen Meldungen keine Informationen entnehmen.
Klick doch mal auf Wiederholen in der zweiten Meldung, dann müsste der Debugger in die zeile springen, in der der Fehler auftritt.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
05.10.2004, 10:53 Uhr
BAR



Ach so, tut mir Leid. Wenn ich auf wiederholen klicke bei der Debug Assertion schliesst er es einfach aber das Fenster mit dem ersten Fehler bleibt immernoch da. Wenn ich da auf Abbrechen gehe springt er zu der Zeile wo er den Speicherfehler hat, ich denk mit Adressen kannst du wenig anfangen

Aber das müsste es sein denke ich:

C++:
...
else
   {
      // should be a normal window
      ASSERT(::IsWindow(m_hWnd));

      // should also be in the permanent or temporary handle map
      CHandleMap* pMap = afxMapHWND();
      ASSERT(pMap != NULL);

      CObject* p;
      ASSERT((p = pMap->LookupPermanent(m_hWnd)) != NULL ||
         (p = pMap->LookupTemporary(m_hWnd)) != NULL);
      ASSERT((CWnd*)p == this);   // must be us

      // 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.
   }
...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
05.10.2004, 11:23 Uhr
proga



Tritt der Fehler in der ersten Zeile auf? dann hast du kein gültiges Handle auf das Window-Objekt mehr, warum ,musst du herausfinden

Jedenfalls kann der Fehler eigentlich nur in deiner funktion liegen, die halt NICHT
multithread-fähig ist. Du musst genau darauf achten welche Objekte du in deinem Thread
benutzt und wie du auf die Objekte zugreifst.

Was ich jetzt machen würde, ich würde Haltepunkte setzen und gucken, welcher Aufruf in
meinem Thread einen Fehler hervorruft. Du musst also gucken, bis wo deine Funktion ohne Fehler ausgeführt wird.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
05.10.2004, 11:31 Uhr
BAR



Danke für deine Mühe. Ich hab mir das Ganze Step für Step angeschaut und du hattest Recht, er hat Probleme beim Zugriff auf die Membervariablen in meinem Hauptdialog:


C++:
UINT CRouteSortDlg::ProcessSeparatingThread(LPVOID pParam)
{
    CRouteSortDlg* pDlg = (CRouteSortDlg*) pParam;

    while(pDlg->m_Flag == 1)
    {
        pDlg->ProcessSeparating();
    }

    delete pDlg;

    return 0;
}

void CRouteSortDlg::ProcessSeparating()
{
        [b]UpdateData(TRUE);[/b]

    while(m_Flag == 1)
    {
        CAddFunctions    AF;
        CPathSplit        CPS;

        int                GSCheck = 0;
        BOOL            checkFolderExistence;
        CString            baseFolder;
        CString            GSFolderName;
        ...

        [b]m_ctlStaticStatusCaption.SetWindowText("Separating:");
        m_ctlStaticStatus.SetWindowText(psCurrentFile);[/b]

        [b]GetMeasDoc(psCurrentFile);[/b]
                    
        [b]TD1 = GetDatabaseInformation(routeInfoFS);[/b]

        ...

    [b]UpdateData(FALSE);[/b]
}


Bei den Sachen die im [b]-Tag stehen (gehört nicht zu meinem Code) hat er Probleme und sobald er da draufkommt springt er zu der ersten Zeile von ProcessSeparatingThread() zurück. Aber ich MUSS in der Funktion Ausgaben machen, umgehen kann ich das nicht. Wie kann man aus einem anderen Thread im Hauptdialog Änderungen machen bei den Elementen?

Dieser Post wurde am 05.10.2004 um 11:31 Uhr von BAR editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
05.10.2004, 14:14 Uhr
proga



hi, also, hab jetzt was gefunden,

du darfst UpdateData nicht aus einem Thread aufrufen. Du musst eine benutzerdefinierte Message an deine Dialogklasse senden und im Message-Handler dann UpdateData aufrufen.


kannst du hier nachlesen

www.c-plusplus.de/forum/viewtopic.php?t=84596&highlight=thread+updatedata
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
05.10.2004, 14:48 Uhr
BAR



Den Thread habe ich auch gesehen und bin dadurch ja auch auf meine Annahme gekommen. Ich hab UpdateData() rausgenommen und habe festgestellt, dass er, sobald er zu irgend einer Ausgabe kommt (auch wenn es ein Control ist der kein UpdateData erfordert), wieder zum ProcessSeparatingThread() an den Anfang zurückgeht.

Ich habe jetzt die komplette Funktion die in ProcessSeparating() ist in ProcessSeparatingThread() genommen und JEDE Variable die ich benutze mit dem Pointer benutzt. Zum Beispiel die Zeile "pDlg->m_ctlStaticStatusCaption.SetWindowText("Separating:");" sollte nach DIESEM Thread funktionieren, tut es aber nicht. Ich hab ihm den Pointer gesetzt, er weiss um welchen Dialog es sich handelt, trotzdem springt er immer und immer und immer und immer und immer wieder zum Anfang zurück...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
05.10.2004, 15:36 Uhr
proga



hörmal, dieses Rumspringen kann ich mir nicht vorstellen,
sowas macht ein Thread nicht. Dieser Effekt ist die folge deiner Schleife in der Methode
ProcessSeparatingThread. Da rufst du die Methode ProcessSeparating auf, solange das Flag
gesetzt ist. Vielleicht hast du dich vertan und meintest eine If-Abfrage ???!


C++:
while(pDlg->m_Flag == 1) // diese Bedingung hat deinen "Sprung-Effekt" zur Folge
{
    pDlg->ProcessSeparating();
}



zu SetWindowText:

ich glaube, da hast du was falsch verstanden. Du musst nicht die Methode SetWindowText
der Klasse CWnd aufrufen, sondern die API-Funktion SetWindowText. Dieser übergibst du
ein Handle deines Steuerelements.

Und nun ein zu Threads allgemein:
Grundsätzlich ist es gefährlich, MFC-Objekte threadübergreifend zu nutzen,
da du nicht davon ausgehen kannst, dass das Objekt immer vorhanden ist
(Diese Regel gilt nicht für Objekte, die direkt von CObject abgeleitet sind oder
von einfachen Klassen wie CRect oder CString).
Stattdessen sollte man mit dem Hauptthread über Messages kommunizieren.
Dazu muss der Arbeitsthread ein Handle auf das Objekt haben.

Also, z.B.

du hast eine Klasse CMyDlg
und eine Methode MyThreadProc, die static deklariert ist

Du startest den Thread mit AfxBeginThread und übergibst diesem ein Handle für
dein Dialog-Objekt. Dann kannst du Message verschicken:


C++:
// in einer Methode der Dialogklasse
AfxBeginThread(MyThreadProc, GetSafeHwnd());

// in der Threadfunktion
::PostMessage((HWND) pParam, WM_MYMESSAGE, 0, 0);



Du musst natürlich auf diese Message auch reagieren, also schreibst du dafür einen Messagehandler.

Dieser Post wurde am 05.10.2004 um 15:39 Uhr von proga editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ VC++ / MFC ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: