Menu

thread hangs on Terminate()

Help
2001-08-23
2001-08-30
  • Christopher Kelly

    I'm having some problems with the Thread::Terminate() method hanging. The problem seems to get worse as the number of threads attempting to terminate in succession increases. Here's the backtrace:
    <pre>
    0x402d5362 in sigsuspend () from /lib/libc.so.6
    (gdb) bt
    #0  0x402d5362 in sigsuspend () from /lib/libc.so.6
    #1  0x4029abc0 in __pthread_wait_for_restart_signal (self=0x402a4940) at pthread.c:934
    #2  0x402978ae in pthread_join (thread_id=31776, thread_return=0x0) at restart.h:34
    #3  0x4015d4d4 in cc_Thread::Terminate (this=0x80abb38) at thread.cpp:331
    #4  0x0805ad02 in Retriever::~Retriever (this=0x80abb38, __in_chrg=3) at Retriever.cc:160
    #5  0x08054fdd in NetworkUsageManager::stop (this=0xbffff700) at NetworkUsageManager.cc:164
    #6  0x08054f73 in NetworkUsageManager::run (this=0xbffff700) at NetworkUsageManager.cc:147
    #7  0x0805438e in NetworkUsageManager::NetworkUsageManager (this=0xbffff700, methods_per_retriever=3, db_pool_size=2, hup_period=10) at NetworkUsageManager.cc:25
    #8  0x08062050 in run (signo=0) at numd.cc:25
    #9  0x080621dc in main (argc=1, argv=0xbffff7d4) at numd.cc:47
    #10 0x402c41f0 in __libc_start_main () from /lib/libc.so.6

    [cck197@shimano num-0.1]$ ldd numd
            libpq++.so.3 => /usr/lib/libpq++.so.3 (0x40027000)
            libsnmp-0.4.2.1.so => /usr/local/lib/libsnmp-0.4.2.1.so (0x40032000)
            libdl.so.2 => /lib/libdl.so.2 (0x40088000)
            libcrypto.so.0 => /usr/lib/libcrypto.so.0 (0x4008c000)
            libccxx-1.5.so.0 => /usr/local/lib/libccxx-1.5.so.0 (0x4014d000)
            libeasysoap.so.0 => /usr/local/lib/libeasysoap.so.0 (0x40168000)
            libexpat.so.0 => /usr/lib/libexpat.so.0 (0x401b6000)
            libssl.so.0 => /usr/lib/libssl.so.0 (0x401e0000)
            libnsl.so.1 => /lib/libnsl.so.1 (0x4020e000)
            libstdc++-libc6.2-2.so.3 => /usr/lib/libstdc++-libc6.2-2.so.3 (0x40225000)
            libm.so.6 => /lib/libm.so.6 (0x4026d000)
            libpthread.so.0 => /lib/libpthread.so.0 (0x40291000)
            libc.so.6 => /lib/libc.so.6 (0x402a8000)
            libpq.so.2 => /usr/lib/libpq.so.2 (0x403d7000)
            /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
            libcrypt.so.1 => /lib/libcrypt.so.1 (0x403e8000)
            libresolv.so.2 => /lib/libresolv.so.2 (0x40417000)

    gcc version 2.96 20000731 (Mandrake Linux 8.1 2.96-0.58mdk)
    </pre>
    Any help would be much appreciated!

     
    • Christopher Kelly

      It seems that I can help myself: here's some code that will reproduce the feature:
      <code>It seems I can help myself: Here's some code that #include <iostream>
      #include <cc++/config.h>
      #include <cc++/macros.h>
      #include <cc++/thread.h>

      class Chimp : public Thread
      {
          protected:
              void Run ( void )
              {
                  const char* function_name = "Chimp::Run";
                  cerr << function_name << endl;
                  unsigned int foo = 0;
                  while ( true )
                  {
                      Yield();
                      continue;
                  }
              }
          public:
              virtual ~Chimp ( )
              {
                  const char* function_name = "Chimp::~Chimp";
                  cerr << function_name << endl;
                  Terminate();
              }
      };

      int
      main ( int argc, char* argv[] )
      {
          const char* function_name = "test::main";
          cerr << function_name << " creating chimp" << endl;;
          Chimp* chimp = new Chimp;
          cerr << function_name << " starting chimp" << endl;
          chimp->Start();
          // give someone else a chance to run
          sleep( 3 );
          cerr << function_name << " deleting chimp" << endl;
          delete chimp;
          cerr << function_name << " done" << endl;
      }#include <iostream>
      #include <cc++/config.h>
      #include <cc++/macros.h>
      #include <cc++/thread.h>

      class Chimp : public Thread
      {
          protected:
              void Run ( void )
              {
                  const char* function_name = "Chimp::Run";
                  cerr << function_name << endl;
                  unsigned int foo = 0;
                  while ( true )
                  {
                      // Yield();
                      continue;
                  }
              }
          public:
              virtual ~Chimp ( )
              {
                  const char* function_name = "Chimp::~Chimp";
                  cerr << function_name << endl;
                  Terminate();
              }
      };

      int
      main ( int argc, char* argv[] )
      {
          const char* function_name = "test::main";
          cerr << function_name << " creating chimp" << endl;;
          Chimp* chimp = new Chimp;
          cerr << function_name << " starting chimp" << endl;
          chimp->Start();
          // give someone else a chance to run
          sleep( 3 );
          cerr << function_name << " deleting chimp" << endl;
          delete chimp;
          cerr << function_name << " done" << endl;
      }
      </code>
      It would seem that the running thread will not be pre-empted when the Terminate() method is called from another thread unless it yields somewhere explicitly. The error in my code had previously been disguised by the thread having it's Terminate   method called whilst it was sleeping, which obviously automatically yields control.

       
      • Anonymous

        Anonymous - 2001-08-30

            Hello,

            It seems (look inside execHandler
        function in thread.cpp) that when
        threads start to run, if you do not call
        `setCancel' between object creation and invoking
        thread_object->Start(), its cancellation status
        is THREAD_CANCEL_DEFAULT, which is defined as
        THREAD_CANCEL_DEFERRED in thread.h.  I have not
        found this documented in the doxygen reference,
        so I post a little patch for this down here,
        although I am not sure if this issue can be
        problematic in some platforms.  To confirm our
        suppositions, try removing the Yield() and using
        setCancel(THREAD_CANCEL_INMEDIATE) before
        invoking Start in the main function, or in
        Chimp::Run.

            BTW, I remember now I have already seen several posts from people asking for basic examples on Common C++ threads. Would not it be nice to include your code in the demo dir? I think you could add some brief comment and send it to the list or one of the developers. If you do not have time but give me permission, I would do it myself.

        ------------------------------------------------

        --- cvsroot/commoncpp/posix/thread.h    Mon Jun 25 18:18:49 2001
        +++ thread.h    Thu Aug 30 11:28:30 2001
        @@ -862,12 +862,17 @@
          *
          * As noted earlier, threads are considered running until the "Run" method
          * returns, or until a cancellation request is made.  Common C++ threads can
        - * control how they respond to cancellation, using setCancellation().
        + * control how they respond to cancellation, using setCancel().
          * Cancellation requests can be ignored, set to occur only when a
        - * cancellation "point" has been reached in the code, or occur immediately.
        - * Threads can also exit by returning from Run() or by invoking the Exit()
        + * cancellation "point" has been reached in the code, or occur immediately.
        + * Threads can also exit by returning from Run() or by invoking the Exit()
          * method.
          *
        + * By default, Common C++ threads are created with deferred cancellation.
        + * If you want your thread to start running with inmediate or disabled
        + * cancellation, do not forget calling setCancel() before calling the Start()
        + * method or inside you Run() method.
        + *
          * Generally it is a good practice to initialize any resources the thread may
          * require within the constructor of your derived thread class, and to purge
          * or restore any allocated resources in the destructor.  In most cases, the

         
        • Christopher Kelly

          Yes, your findings are correct. I had tried this quickly before, and it had no effect because I called setCancel in the constructor of the thread object. Here's the code:

          #include <iostream>
          #include <cc++/config.h>
          #include <cc++/macros.h>
          #include <cc++/thread.h>

          class Chimp : public Thread
          {
              protected:
                  void Run ( void )
                  {
                      const char* function_name = "Chimp::Run";
                      setCancel( THREAD_CANCEL_IMMEDIATE );
                      cerr << function_name << " cancel mode: " << getCancel() << endl;
                      while ( true )
                      {
                          // Yield();
                          continue;
                      }
                  }
              public:
                  Chimp ( )
                  {
                      const char* function_name = "Chimp::Chimp";
                      cerr << function_name << endl;
                      // setting the cancel mode here won't work!
                      // setCancel( THREAD_CANCEL_IMMEDIATE );
                  }
                  virtual ~Chimp ( )
                  {
                      const char* function_name = "Chimp::~Chimp";
                      cerr << function_name << endl;
                      Terminate();
                  }
          };

          int
          main ( int argc, char* argv[] )
          {
              const char* function_name = "test::main";
              cerr << function_name << " creating chimp" << endl;;
              Chimp* chimp = new Chimp;
              cerr << function_name << " starting chimp" << endl;
              chimp->Start();
              // give someone else a chance to run
              sleep( 3 );
              cerr << function_name << " deleting chimp" << endl;
              delete chimp;
              cerr << function_name << " done" << endl;
          }

          It seems trivial, but I guess this code snippet could save people time getting into the basics of creating threads with CommonC++, I'll make another  posting...

          Thanks for the response.

           
          • David Sugar

            David Sugar - 2001-08-30

            Cancellation points are an oddity in pthread implimentations.  Some systems impliment sufficient numbers of them, and some do not.  Most will cancel on an i/o operation, but not all.  Hence, Yield should be used in any loops in threads that may otherwise run forever so they can always be cancelled, if deferred mode cancellation is used.  Using immediate has risks in some pthread systems if it happens in the wrong place (like in the middle of a semaphore operation).

            That being said, it would be nice to have a nice and simple example to use in the demos directory.

             

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.