Announcement

Collapse
No announcement yet.

Thread: OnTerminate-Event bleibt aus

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Thread: OnTerminate-Event bleibt aus

    Hallo,

    ich habe ein ganz komisches Verhalten bei meinen Threads. Eigentlich sollte beim Beenden eine Funktion durchlaufen werden, welche ich auch dem OnTerminate-Event zugeordnet habe, aber die Funktionen werden bei keinem Thread aufgerufen. Hat jemand einen Tipp?

    Michael

    Hier ein paar Auszüge:

    MyThread = new TMyThread(true); MyThread->FreeOnTerminate = true; MyThread->OnTerminate = MyFunc; MyThread->Priority = tpNormal; MyThread->Resume();

    . . .

    MyThread->Terminate();

    ...

    void __fastcall MyThread::Execute() { while(!Terminated) { sleep(1); }

    ...

    }

    void __fastcall Form1::MyFunc (TObject* Sender) { Counter--; Beep(); // :-) }

    Was mache ich falsch? Michael

  • #2
    new TMyThread(true);

    sollte wohl

    new TMyThread(false);

    Sonst startet der Thread nicht

    Hier habe ich dir ein Demo aus deinen Daten hingelegt:

    http://home.snafu.de/christian.marquardt/links.7/demo.zi
    Christian

    Comment


    • #3
      Hallo !

      nein, nein, new TMyThread(true) ist schon in Ordnung. Der Thread wird ja dann mit TMyThread->Resume() gestartet. Laufen tut er ja auch, das ist nicht das Problem.

      Ich hab' auch schon selbst ein kleinen "Test"-Prog geschrieben, deinem ganz ähnlich. Und dort funktioniert alles wunderbar (wie in deinem ja auch). Aber in meiner großen Anwendung funktioniert das mit der OnTerminate-Funktion nicht...

      Was kann man denn noch falsch machen?
      Gibt es etwas Besonderes zu bedenken, wenn man mehrere Threads laufen hat (hier 6)?

      In meinen OnTerminate-Funktionen soll jeder Thread auf eine globale Variable zugreifen und sie inkrementieren (Zugriff wird mit einem TCriticalSection-Block abgesichert). Die Hauptanwendung beendet alle Threads und fragt ca. 3 Sekunden später Variable ab. Diese wurde aber nie inkrementiert (überall sind Break-Points)...

      Ich verzweifle :-)

      Michae

      Comment


      • #4
        Ja, Stimmt, das Resume habe ich übersehen.

        Mir fällt nur noch auf, dass MyFunc zur Klasse Form1 gehört und nicht zur Thread-Klasse. Ob das eine Rolle spiel weiß ich nicht. Das "Rufen Sie Synchronize nicht aus dem VCL-Haupt-Thread aus auf. Dies würde zu einer Endlosschleife führen." spielt wohl keine Rolle??

        Ansonsten kann ich dir nur den Quelltext von
        http://home.snafu.de/christian.marquardt/programme.4/4_gethostname.html
        anbieten
        Christian

        Comment


        • #5
          Hallo Michael,

          vielleicht hilft Dir das weiter:
          <PRE>
          clThread->Terminate();´
          //schäft der Thread ?
          if (clThread->Suspended)
          //Falls der Thread schläft,aufwachen clThread->Resume();
          // Warte bis Thread beendet clThread->WaitFor();
          </PRE>

          Gruß
          Gerhar

          Comment


          • #6
            Hallo Gerhard,

            ein Zugriff auf eine Instanz des Threads, welcher zuvor mit Terminate veranlasst wurde, sich zu beenden, kann bei "FreeonTerminate = true" dazu führen, dass das Objekt beim Zugriff mit "Waitfor" garnicht mehr existiert. Es kommt also zu einer Exception.

            Aber ich hatte ganz vergessen, dass meine Thread ja in meiner dll laufen und nicht in meiner Hauptanwendung.

            Kann hier das Problem liegen?

            Michae

            Comment


            • #7
              Auf die Variablen einer DLL kann immer nur eine Anwendung zugreifen bzw. Jede Anwendung die diese DLL nutzt bekommt einen eigenen Satz der Variablen. Das betrifft auch und insbesondere die globalen Variablen. Offenbar gilt das auch für Threads.

              Abhilfe kann hier sein:

              Werte in die Registry speichern oder gemeinsam genutzen Speicher benutzen.

              Hier die Windows SDK Hilde zu shared Memory:

              This section shows how the DLL entry-point function can use a file-mapping object to set up memory that can be shared by processes that load the DLL. The shared DLL memory persists only as long as the DLL is loaded.

              The example uses file mapping to map a block of named shared memory into the virtual address space of each process that loads the DLL. To do this, the entry-point function must:

              1. Call the CreateFileMapping function to get a handle to a file-mapping object. The first process that loads the DLL creates the file-mapping object. Subsequent processes open a handle of the existing object. For more information, see Creating a File-Mapping Object.
              2. Call the MapViewOfFile function to map a view into the virtual address space. This enables the process to access the shared memory. For more information, see Creating a File View.



              // File: DLLSHMEM.C.
              // The DLL entry-point function sets up shared memory using
              // a named file-mapping object.

              #include <windows.h>
              #include <memory.h>

              #define SHMEMSIZE 4096

              static LPVOID lpvMem = NULL; // pointer to shared memory

              BOOL DllEntryPoint(HINSTANCE hinstDLL, // DLL module handle
              DWORD fdwReason, // reason called
              LPVOID lpvReserved) // reserved
              {
              HANDLE hMapObject = NULL; // handle to file mapping

              BOOL fInit, fIgnore;

              switch (fdwReason)
              {
              // The DLL is loading due to process
              // initialization or a call to LoadLibrary.

              case DLL_PROCESS_ATTACH:

              // Create a named file mapping object.

              hMapObject = CreateFileMapping(
              (HANDLE) 0xFFFFFFFF, // use paging file
              NULL, // no security attributes
              PAGE_READWRITE, // read/write access

              0, // size: high 32-bits
              SHMEMSIZE, // size: low 32-bits
              "dllmemfilemap"); // name of map object
              if (hMapObject == NULL)
              return FALSE;

              // The first process to attach initializes memory.

              fInit = (GetLastError() != ERROR_ALREADY_EXISTS);

              // Get a pointer to the file-mapped shared memory.

              lpvMem = MapViewOfFile(

              hMapObject, // object to map view of
              FILE_MAP_WRITE, // read/write access
              0, // high offset: map from
              0, // low offset: beginning
              0); // default: map entire file
              if (lpvMem == NULL)
              return FALSE;

              // Initialize memory if this is the first process.

              if (fInit)
              memset(lpvMem, '\0', SHMEMSIZE);


              break;

              // The attached process creates a new thread.

              case DLL_THREAD_ATTACH:
              break;

              // The thread of the attached process terminates.

              case DLL_THREAD_DETACH:
              break;

              // The DLL is unloading from a process due to
              // process termination or a call to FreeLibrary.

              case DLL_PROCESS_DETACH:

              // Unmap shared memory from the process's address space.


              fIgnore = UnmapViewOfFile(lpvMem);

              // Close the process's handle to the file-mapping object.

              fIgnore = CloseHandle(hMapObject);

              break;

              default:
              break;
              }

              return TRUE;
              UNREFERENCED_PARAMETER(hinstDLL);
              UNREFERENCED_PARAMETER(lpvReserved);
              }

              // SetSharedMem sets the contents of shared memory.

              VOID SetSharedMem(LPTSTR lpszBuf)
              {
              LPTSTR lpszTmp;


              // Get the address of the shared memory block.

              lpszTmp = (LPTSTR) lpvMem;

              // Copy the null-terminated string into shared memory.

              while (*lpszBuf)
              *lpszTmp++ = *lpszBuf++;
              *lpszTmp = '\0';
              }

              // GetSharedMem gets the contents of shared memory.

              VOID GetSharedMem(LPTSTR lpszBuf, DWORD cchSize)
              {
              LPTSTR lpszTmp;

              // Get the address of the shared memory block.

              lpszTmp = (LPTSTR) lpvMem;

              // Copy from shared memory into the caller's buffer.


              while (*lpszTmp && --cchSize)
              *lpszBuf++ = *lpszTmp++;
              *lpszBuf = '\0';
              }


              Note that the shared memory can be mapped to a different address in each process. For this reason, each process has its own instance of the lpvMem parameter, which is declared as a global variable so that it is available to all DLL functions. The example assumes that the DLL global data is not shared, so each process that loads the DLL has its own instance of lpvMem.
              In this example, the shared memory is released when the last handle of the file-mapping object is closed. To create persistent shared memory, a DLL can create a detached process (see CreateProcess) when the DLL is first loaded. If this detached process uses the DLL and does not terminate, it has a handle of the file-mapping object that prevents the shared memory from being released.
              &#10
              Christian

              Comment


              • #8
                Hallo Michael,

                bei meinem Bsp. bin ich nicht davon ausgegangen den Thread auf FreeOnTerminate = true zu setzen. Ich würde ansonsten bestimmt kein WaitFor benutzen. Nun aber zurück zu Deiner Frage.
                1.)Läuft der Thread überhaupt nicht, oder wird nur FreeOnTerminate nicht aufgerufen ?
                2.)
                Wie linkst Du die DLL statisch oder dynamisch ?
                Was Christian schreibt stimmt. Trifft aber nur für den Fall zu, dass mehrere Programme (jedes Programm ja läuft in einem eigenen Prozess) diese DLL benutzen wollen bzw. müssen. So wie ich es verstanden habe, ist das aber nicht bei Dir der Fall, oder ?

                Gruß
                Gerhar

                Comment


                • #9
                  Mich würde interessieren:

                  Gilt das für den eigenen Speicherbereich für jedes Programm bezogen auf die DLL auch für Threads?

                  Da die globalen Variablen im Thread von Michael NICHT verändert werden, scheint es doch so zu sein??

                  Jeder Thread in einer DLL sein eigenen Speicher?
                  Christian

                  Comment


                  • #10
                    Hallo Christian & Gerhard !

                    Erst einmal vielen Dank für Eure Mühe !!!

                    Also meine DLL wird (im Moment zumindest) nur von einer Anwendung verwendet. Ich hab sogar schon jedem Thread seine eigene (!!) OnTerminate-Funktion gegeben. Aber alles ohne Erfolg. Wenn ich in den Threads eine Anweisung nach while(!Terminated){......} hinzufüge, wird diese auch sauber ausgeführt, nachdem ich den Thread beende, aber die OnTerminate-Funktion wird nur bei einem Thread angesprungen.

                    Also: - Alle Threads laufen ohne Problem und eine Programmmzeile nach while(!Terminated){......} wird überall ausgeführt.

                    - Die DLL wird statisch gelinkt.
                    - Der Objektinspektor zeigt auch bei jedem Thread, dass das OnTerminate-Property die Adresse der Terminate-Funktion enthält.

                    Also müsste es eigentlich funktionieren... ;-(
                    Ich hab' auch schon gedacht, dass die OnTerminate-Funktion für irgendeinen Thread nicht zugänglich sein könnte (weil z.B. private), aber dem war nicht so. Und spätestens nach meiner Version mit den eigenen Funktionen ist das ja eh kein Thema mehr.

                    Gruß Michae

                    Comment

                    Working...
                    X